diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 194e2e589..73df543f1 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -150,6 +150,12 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
+
+
{
dialog.dismiss();
startActivity(new Intent(context, Preferences.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/NewDataObserver.java b/app/src/main/java/com/eveningoutpost/dexdrip/NewDataObserver.java
index 6d8ed221c..86cef53f3 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/NewDataObserver.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/NewDataObserver.java
@@ -4,6 +4,7 @@
import com.eveningoutpost.dexdrip.models.JoH;
import com.eveningoutpost.dexdrip.models.LibreBlock;
import com.eveningoutpost.dexdrip.models.UserError;
+import com.eveningoutpost.dexdrip.receiver.InfoContentProvider;
import com.eveningoutpost.dexdrip.sharemodels.BgUploader;
import com.eveningoutpost.dexdrip.sharemodels.models.ShareUploadPayload;
import com.eveningoutpost.dexdrip.utilitymodels.Inevitable;
@@ -58,6 +59,7 @@ public static void newBgReading(BgReading bgReading, boolean is_follower) {
sendToBlueJay();
sendToRemoteBlueJay();
Notifications.start();
+ InfoContentProvider.ping("bg");
uploadToShare(bgReading, is_follower);
textToSpeech(bgReading, null);
LibreBlock.UpdateBgVal(bgReading.timestamp, bgReading.calculated_value);
@@ -87,6 +89,7 @@ public static void newExternalStatus(boolean receivedLocally) {
GcmActivity.push_external_status_update(JoH.tsl(), statusLine);
}
+ InfoContentProvider.ping("status");
}
}
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/StartNewSensor.java b/app/src/main/java/com/eveningoutpost/dexdrip/StartNewSensor.java
index 82da7f965..c01bb1791 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/StartNewSensor.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/StartNewSensor.java
@@ -61,17 +61,22 @@ public class StartNewSensor extends ActivityWithMenu {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (!Sensor.isActive()) {
- JoH.fixActionBar(this);
- setContentView(R.layout.activity_start_new_sensor);
- button = (Button) findViewById(R.id.startNewSensor);
- //dp = (DatePicker)findViewById(R.id.datePicker);
- //tp = (TimePicker)findViewById(R.id.timePicker);
- addListenerOnButton();
- } else {
- Intent intent = new Intent(this, StopSensor.class);
- startActivity(intent);
+ if (DexCollectionType.getBestCollectorHardwareName().equals("G7")) {
+ JoH.static_toast_long(getString(R.string.g7_should_start_automatically));
finish();
+ } else {
+ if (!Sensor.isActive()) {
+ JoH.fixActionBar(this);
+ setContentView(R.layout.activity_start_new_sensor);
+ button = (Button) findViewById(R.id.startNewSensor);
+ //dp = (DatePicker)findViewById(R.id.datePicker);
+ //tp = (TimePicker)findViewById(R.id.timePicker);
+ addListenerOnButton();
+ } else {
+ Intent intent = new Intent(this, StopSensor.class);
+ startActivity(intent);
+ finish();
+ }
}
}
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/cloud/backup/BackupActivity.java b/app/src/main/java/com/eveningoutpost/dexdrip/cloud/backup/BackupActivity.java
index 002396f95..f1887c7eb 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/cloud/backup/BackupActivity.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/cloud/backup/BackupActivity.java
@@ -17,6 +17,7 @@
import com.eveningoutpost.dexdrip.models.JoH;
import com.eveningoutpost.dexdrip.models.UserError;
import com.eveningoutpost.dexdrip.R;
+import com.eveningoutpost.dexdrip.receiver.InfoContentProvider;
import com.eveningoutpost.dexdrip.utilitymodels.Inevitable;
import com.eveningoutpost.dexdrip.utilitymodels.PrefsViewImpl;
import com.eveningoutpost.dexdrip.databinding.ActivityBackupPickerBinding;
@@ -212,6 +213,7 @@ private synchronized void restoreNowReal() {
if (metaData.exception != null) {
status(getString(R.string.error_exclamation) + " " + metaData.exception);
}
+ InfoContentProvider.ping("pref");
} finally {
idle.set(true);
}
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/g5model/BaseGlucoseRxMessage.java b/app/src/main/java/com/eveningoutpost/dexdrip/g5model/BaseGlucoseRxMessage.java
index 41d94825b..b39e37f42 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/g5model/BaseGlucoseRxMessage.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/g5model/BaseGlucoseRxMessage.java
@@ -1,5 +1,6 @@
package com.eveningoutpost.dexdrip.g5model;
+import com.eveningoutpost.dexdrip.models.JoH;
import com.eveningoutpost.dexdrip.services.G5CollectionService;
import lombok.NoArgsConstructor;
@@ -50,4 +51,9 @@ public Integer getPredictedGlucose() {
return null; // stub
}
+ public long getRealTimestamp() {
+ return JoH.tsl(); // default behavior is received now
+ }
+
+
}
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/g5model/DexSyncKeeper.java b/app/src/main/java/com/eveningoutpost/dexdrip/g5model/DexSyncKeeper.java
index ecd8fe5c9..31e0c28b7 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/g5model/DexSyncKeeper.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/g5model/DexSyncKeeper.java
@@ -41,6 +41,16 @@ public static void store(final String transmitterId, final long when) {
UserError.Log.d(TAG, "Sync time updated to: " + JoH.dateTimeText(when));
}
+ public static void store(final String transmitterId, final long when, final long last_conection_time, final long last_glucose_processed) {
+ final long latency = (last_glucose_processed - last_conection_time);
+ UserError.Log.d(TAG, "Update time from glucose rx glucose: " + JoH.dateTimeText(when) + " latency:" + latency + " ms");
+ if (latency < 8000) { // roughly half preempt
+ store(transmitterId, when);
+ } else {
+ UserError.Log.e(TAG, "Refusing to update stored timestamp due to excessive processing latency: " + latency + "ms");
+ }
+ }
+
public static void clear(final String transmitterId) {
if (PersistentStore.getLong(DEX_SYNC_STORE + transmitterId) > 0) {
UserError.Log.e(TAG, "Clearing stored timing sync information for: " + transmitterId);
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/g5model/EGlucoseRxMessage2.java b/app/src/main/java/com/eveningoutpost/dexdrip/g5model/EGlucoseRxMessage2.java
index 4b6611689..358b0766c 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/g5model/EGlucoseRxMessage2.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/g5model/EGlucoseRxMessage2.java
@@ -91,6 +91,11 @@ public Long getRealSessionStartTime() {
return null;
}
+ @Override
+ public long getRealTimestamp() {
+ return JoH.tsl() - (age * Constants.SECOND_IN_MS);
+ }
+
public String getRealSessionStartTimeString() {
val t = getRealSessionStartTime();
if (t != null) {
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/g5model/Ob1G5StateMachine.java b/app/src/main/java/com/eveningoutpost/dexdrip/g5model/Ob1G5StateMachine.java
index adb22b6a8..26017ca41 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/g5model/Ob1G5StateMachine.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/g5model/Ob1G5StateMachine.java
@@ -82,6 +82,8 @@
import static com.eveningoutpost.dexdrip.services.Ob1G5CollectionService.STATE.SCAN;
import static com.eveningoutpost.dexdrip.services.Ob1G5CollectionService.android_wear;
import static com.eveningoutpost.dexdrip.services.Ob1G5CollectionService.getTransmitterID;
+import static com.eveningoutpost.dexdrip.services.Ob1G5CollectionService.ignoreBonding;
+import static com.eveningoutpost.dexdrip.services.Ob1G5CollectionService.immediateBonding;
import static com.eveningoutpost.dexdrip.services.Ob1G5CollectionService.onlyUsingNativeMode;
import static com.eveningoutpost.dexdrip.services.Ob1G5CollectionService.resetSomeInternalState;
import static com.eveningoutpost.dexdrip.services.Ob1G5CollectionService.wear_broadcast;
@@ -133,6 +135,7 @@ public class Ob1G5StateMachine {
private static final int OLDEST_RAW = 300 * 24 * 60 * 60; // 300 days
public static long maxBackfillPeriod_MS = 0;
+
public static long maxBackfillPeriod_MS() {
maxBackfillPeriod_MS = MAX_BACKFILL_PERIOD_MS;
if (shortTxId()) { // If using G7
@@ -140,6 +143,7 @@ public static long maxBackfillPeriod_MS() {
}
return maxBackfillPeriod_MS;
}
+
public static int backfillCheckLarge() {
return (int) (maxBackfillPeriod_MS() / DEXCOM_PERIOD);
}
@@ -272,7 +276,7 @@ public static boolean doCheckAuth2(final Ob1G5CollectionService parent, final Rx
connection.setupNotification(ExtraData)
.timeout(15, TimeUnit.SECONDS) // WARN
.doOnNext(notificationObservable -> {
- UserError.Log.d(TAG,"Extra data notifications enabled");
+ UserError.Log.d(TAG, "Extra data notifications enabled");
connection.setupIndication(Authentication)
.timeout(15, TimeUnit.SECONDS) // WARN
.doOnNext(notificationObservable2 -> doNext(parent, connection))
@@ -289,14 +293,14 @@ public static boolean doCheckAuth2(final Ob1G5CollectionService parent, final Rx
doNext(parent, connection);
}
} catch (Exception e) {
- UserError.Log.e(TAG,"Got exception in plugin: " + e);
+ UserError.Log.e(TAG, "Got exception in plugin: " + e);
parent.lastSensorStatus = e.getMessage();
if (e instanceof InvalidParameterException) {
parent.resetSomeInternalState();
} else if (e instanceof SecurityException) {
- parent.logFailure();
- parent.clearPersistStore();
- parent.changeState(SCAN);
+ parent.logFailure();
+ parent.clearPersistStore();
+ parent.changeState(SCAN);
} else {
e.printStackTrace();
}
@@ -323,7 +327,7 @@ public static boolean doCheckAuth2(final Ob1G5CollectionService parent, final Rx
private static void handleAuthenticationWrite(final Ob1G5CollectionService parent, final RxBleConnection connection) {
final int specifiedSlot = Pref.getBooleanDefaultFalse("engineering_mode") ? Pref.getStringToInt("dex_specified_slot", -1) : -1;
final AuthRequestTxMessage authRequest = (specifiedSlot == -1) ? new AuthRequestTxMessage(getTokenSize(), usingAlt())
- : new AuthRequestTxMessage(getTokenSize(), specifiedSlot);
+ : new AuthRequestTxMessage(getTokenSize(), specifiedSlot);
lastAuthPacket = authRequest;
UserError.Log.i(TAG, "AuthRequestTX: " + bytesToHex(authRequest.byteSequence));
@@ -882,7 +886,7 @@ public static boolean doGetData(Ob1G5CollectionService parent, RxBleConnection c
} else {
parent.msg("Invalid Glucose");
}
- break;
+ break;
case CalibrateRxMessage:
@@ -1108,15 +1112,15 @@ private static void backFillIfNeeded(Ob1G5CollectionService parent, RxBleConnect
UserError.Log.d(TAG, "Requesting backfill between: " + JoH.dateTimeText(startTime) + " " + JoH.dateTimeText(endTime));
- if (!shortTxId()) {
- enqueueUniqueCommand(
- BackFillTxMessage.get(getTransmitterID(), startTime, endTime),
- "Get backfill since: " + JoH.hourMinuteString(startTime));
- } else {
- enqueueUniqueCommand(
- BackFillTxMessage2.get(getTransmitterID(), startTime, endTime),
- "Get backfill2 since: " + JoH.hourMinuteString(startTime));
- }
+ if (!shortTxId()) {
+ enqueueUniqueCommand(
+ BackFillTxMessage.get(getTransmitterID(), startTime, endTime),
+ "Get backfill since: " + JoH.hourMinuteString(startTime));
+ } else {
+ enqueueUniqueCommand(
+ BackFillTxMessage2.get(getTransmitterID(), startTime, endTime),
+ "Get backfill2 since: " + JoH.hourMinuteString(startTime));
+ }
} else {
nextBackFillCheckSize = BACKFILL_CHECK_SMALL;
}
@@ -1563,8 +1567,9 @@ private static void processGlucoseRxMessage(Ob1G5CollectionService parent, final
DexTimeKeeper.updateAge(getTransmitterID(), glucose.timestamp);
if (glucose.usable() || (glucose.insufficient() && Pref.getBoolean("ob1_g5_use_insufficiently_calibrated", true))) {
UserError.Log.d(TAG, "Got usable glucose data from transmitter!!");
- final long rxtimestamp = tsl();
+ final long rxtimestamp = glucose.getRealTimestamp();
checkAndActivateSensor();
+ DexSyncKeeper.store(getTransmitterID(), rxtimestamp, parent.static_last_connected, lastGlucosePacket);
final BgReading bgReading = BgReading.bgReadingInsertFromG5(glucose.glucose, rxtimestamp);
if (bgReading != null) {
try {
@@ -1590,7 +1595,7 @@ private static void processGlucoseRxMessage(Ob1G5CollectionService parent, final
if (glucose.getPredictedGlucose() != null) {
// not really supported on wear yet
if (!android_wear) {
- Prediction.create(tsl(), glucose.getPredictedGlucose(), "EGlucoseRx").save();
+ Prediction.create(rxtimestamp, glucose.getPredictedGlucose(), "EGlucoseRx").save();
}
}
@@ -1981,7 +1986,8 @@ private static synchronized byte[] calculateChallengeHash(final byte[] challenge
@SuppressLint("GetInstance") final Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
aesCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
return Arrays.copyOfRange(aesCipher.doFinal(plainText, 0, plainText.length), 0, 8);
- } catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidKeyException e) {
+ } catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException |
+ BadPaddingException | InvalidKeyException e) {
UserError.Log.wtf(TAG, "System Encryption problem: " + e);
return null;
}
@@ -2106,7 +2112,7 @@ private static boolean getEGlucose(final Ob1G5CollectionService parent) {
public static boolean usingAlt() {
return (android_wear && !Pref.getBooleanDefaultFalse("only_ever_use_wear_collector"))
- || WholeHouse.isLive();
+ || (immediateBonding() && !ignoreBonding()) || WholeHouse.isLive();
}
private static class OperationSuccess extends RuntimeException {
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/models/JoH.java b/app/src/main/java/com/eveningoutpost/dexdrip/models/JoH.java
index 99d3101b9..584cea0e3 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/models/JoH.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/models/JoH.java
@@ -1881,6 +1881,17 @@ public static byte[] splitBytes(final byte[] source, final int start, final int
return newBytes;
}
+ public static byte[] joinBytes(final byte[] first, final byte[] second) {
+ if (first == null || second == null) {
+ throw new IllegalArgumentException("Input arrays cannot be null");
+ }
+ final int totalLength = first.length + second.length;
+ final byte[] result = new byte[totalLength];
+ System.arraycopy(first, 0, result, 0, first.length);
+ System.arraycopy(second, 0, result, first.length, second.length);
+ return result;
+ }
+
public static long checksum(byte[] bytes) {
if (bytes == null) return 0;
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/models/UserError.java b/app/src/main/java/com/eveningoutpost/dexdrip/models/UserError.java
index c6b69ff1f..95bfbdc73 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/models/UserError.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/models/UserError.java
@@ -9,6 +9,7 @@
import com.activeandroid.annotation.Table;
import com.activeandroid.query.Delete;
import com.activeandroid.query.Select;
+import com.eveningoutpost.dexdrip.receiver.InfoContentProvider;
import com.eveningoutpost.dexdrip.utilitymodels.Constants;
import com.eveningoutpost.dexdrip.utilitymodels.Pref;
import com.google.gson.annotations.Expose;
@@ -17,7 +18,6 @@
import java.util.Hashtable;
import java.util.List;
-//import com.bugfender.sdk.Bugfender;
/**
* Created by Emma Black on 8/3/15.
@@ -236,6 +236,15 @@ public static List bySeverityOlderThanID(long id, Integer[] levels, i
}
+ public static UserError newestBySeverity(int level) {
+ return new Select()
+ .from(UserError.class)
+ .where("severity == "+level)
+ .orderBy("timestamp desc")
+ .limit(1)
+ .executeSingle();
+ }
+
public static UserError getForTimestamp(UserError error) {
try {
return new Select()
@@ -331,6 +340,7 @@ public static void uel(String tag, String b) {
public static void ueh(String tag, String b) {
android.util.Log.i(tag, b);
UserError.UserEventHigh(tag, b);
+ InfoContentProvider.ping("info");
}
public static void d(String tag, String b) {
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/receiver/InfoContentProvider.java b/app/src/main/java/com/eveningoutpost/dexdrip/receiver/InfoContentProvider.java
new file mode 100644
index 000000000..16205b28b
--- /dev/null
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/receiver/InfoContentProvider.java
@@ -0,0 +1,310 @@
+package com.eveningoutpost.dexdrip.receiver;
+
+import static com.eveningoutpost.dexdrip.utilitymodels.ColorCache.getCol;
+import static com.eveningoutpost.dexdrip.utilitymodels.NanoStatus.nanoStatus;
+import static com.eveningoutpost.dexdrip.utilitymodels.Pref.getBooleanDefaultFalse;
+import static com.eveningoutpost.dexdrip.watch.thinjam.BlueJayEntry.isNative;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.graphics.Bitmap;
+
+import android.net.Uri;
+import android.os.Looper;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.eveningoutpost.dexdrip.BestGlucose;
+import com.eveningoutpost.dexdrip.BuildConfig;
+import com.eveningoutpost.dexdrip.eassist.EmergencyAssist;
+import com.eveningoutpost.dexdrip.models.UserError;
+import com.eveningoutpost.dexdrip.utilitymodels.AlertPlayer;
+import com.eveningoutpost.dexdrip.utilitymodels.BgGraphBuilder;
+import com.eveningoutpost.dexdrip.utilitymodels.BgSparklineBuilder;
+
+import com.eveningoutpost.dexdrip.utilitymodels.CollectionServiceStarter;
+import com.eveningoutpost.dexdrip.utilitymodels.ColorCache;
+import com.eveningoutpost.dexdrip.utilitymodels.Constants;
+import com.eveningoutpost.dexdrip.utilitymodels.Pref;
+import com.eveningoutpost.dexdrip.utils.BlobCache;
+import com.eveningoutpost.dexdrip.xdrip;
+
+import java.io.ByteArrayOutputStream;
+
+/**
+ * xDrip content provider
+ * JamOrHam
+ */
+public class InfoContentProvider extends ContentProvider {
+
+ private static final String TAG = "jamorham-content";
+ private static final BlobCache dgCache = new BlobCache(60_000);
+ private static final BlobCache graphCache = new BlobCache(60_000);
+
+ {
+ xdrip.setContext(getContext());
+ }
+
+ @Override
+ public boolean onCreate() {
+ xdrip.setContext(getContext());
+ return enabled();
+ }
+
+ @Nullable
+ @Override
+ public Cursor query(@NonNull Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ if (!enabled()) return null;
+ try {
+ if (selection == null) return null;
+
+ switch (selection) {
+
+ case "ping":
+ return matrixRow(
+ "version", BuildConfig.VERSION_NAME,
+ "versioncode", BuildConfig.buildVersion);
+
+ case "alarms":
+ if (selectionArgs.length > 0 && selectionArgs[0].equals("snooze")) {
+ AlertPlayer.getPlayer().OpportunisticSnooze();
+ Log.d(TAG, "Opportunistic snooze");
+ }
+ break;
+
+ case "eassist":
+ if (enabledWrite()) {
+ EmergencyAssist.test(EmergencyAssist.Reason.REQUESTED_ASSISTANCE, Constants.MINUTE_IN_MS);
+ UserError.Log.ueh(TAG, "Emergency assist triggered remotely");
+ }
+ break;
+
+ case "bg": {
+ BestGlucose.DisplayGlucose dg = (BestGlucose.DisplayGlucose) dgCache.get();
+ if (dg == null) {
+ dg = BestGlucose.getDisplayGlucose();
+ dgCache.set(dg);
+ }
+ if (dg == null) return null;
+
+ int chint = getCol(ColorCache.X.color_inrange_bg_values);
+ if (dg.isHigh()) {
+ chint = getCol(ColorCache.X.color_high_bg_values);
+ } else if (dg.isLow()) {
+ chint = getCol(ColorCache.X.color_low_bg_values);
+ }
+ return matrixRow(
+ "timestamp", dg.timestamp,
+ "mgdl", dg.mgdl,
+ "delta_mgdl", dg.delta_mgdl,
+ "delta_arrow", dg.delta_arrow,
+ "delta_name", dg.delta_name,
+ "mssince", dg.mssince,
+ "unitized", dg.unitized,
+ "unitized_delta", dg.unitized_delta,
+ "unitized_delta_no_units", dg.unitized_delta_no_units,
+ "chint", chint,
+ "humansummary", dg.humanSummary(),
+ "ishigh", boolInt(dg.isHigh()),
+ "islow", boolInt(dg.isLow()),
+ "isstale", boolInt(dg.isStale()),
+ "isreallystale", boolInt(dg.isReallyStale())
+ );
+ }
+
+ case "status-line": {
+ }
+ break;
+
+ case "nano-status": {
+ return matrixRow(
+ "collector", nanoStatus("collector"),
+ "sensor-expiry", nanoStatus("sensor-expiry")
+ );
+ }
+
+ case "info":
+ return matrixRow("last_ueh", UserError.newestBySeverity(6));
+
+ case "iob-info": {
+ }
+ break;
+
+ case "graph": {
+
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ final int width = Math.min(1000, Integer.parseInt(selectionArgs[0]));
+ final int height = Math.min(1000, Integer.parseInt(selectionArgs[1]));
+
+ byte[] blob = (byte[]) graphCache.get(width, height);
+ if (blob == null) {
+ String backgroundColor = "#80000000";
+ if (selectionArgs.length >= 3) {
+ backgroundColor = selectionArgs[2];
+ }
+
+ final BgGraphBuilder bgGraphBuilder = new BgGraphBuilder(xdrip.getAppContext());
+
+ final Bitmap bitmap = new BgSparklineBuilder(xdrip.getAppContext())
+ .setBgGraphBuilder(bgGraphBuilder)
+ .setHeight(height)
+ .setDotSize(5)
+ .setWidth(width)
+ .showHighLine(true)
+ .showLowLine(true)
+ .build();
+ blob = convertBitmapToPNGByteArray(bitmap);
+ bitmap.recycle();
+ graphCache.set(blob, width, height);
+ }
+
+ final String[] columnNames = {"blob"};
+ final MatrixCursor cursor = new MatrixCursor(columnNames);
+ cursor.addRow(new Object[]{blob});
+ return cursor;
+ }
+
+ case "config":
+ if (enabledWrite()) {
+ try {
+ if (selectionArgs != null && projection != null
+ && selectionArgs.length == projection.length) {
+ for (int i = 0; i < projection.length; i++) {
+ final String item = projection[i];
+ switch (sortOrder) {
+ case "String":
+ Pref.setString(item, selectionArgs[i]);
+ break;
+ case "Integer":
+ Pref.setInt(item, Integer.parseInt(selectionArgs[i]));
+ break;
+ case "Long":
+ Pref.setLong(item, Long.parseLong(selectionArgs[i]));
+ break;
+ case "Boolean":
+ Pref.setBoolean(item, Boolean.parseBoolean(selectionArgs[i]));
+ break;
+ case "NewString":
+ if (Pref.getString(item, "defaultvalue").equals("defaultvalue")) {
+ Pref.setString(item, selectionArgs[i]);
+ }
+ break;
+ case "NewInteger":
+ if (Pref.getInt(item, -1000) == -1000) {
+ Pref.setInt(item, Integer.parseInt(selectionArgs[i]));
+ }
+ break;
+ case "NewLong":
+ if (Pref.getLong(item, -1000) == -1000) {
+ Pref.setLong(item, Long.parseLong(selectionArgs[i]));
+ }
+ break;
+ case "NewBoolean":
+ if (Pref.isPreferenceSet(item)) {
+ Pref.setBoolean(item, Boolean.parseBoolean(selectionArgs[i]));
+ }
+ break;
+ case "Remove":
+ Pref.removeItem(item);
+ break;
+ }
+ }
+ CollectionServiceStarter.restartCollectionServiceBackground();
+ return matrixRow("processed", projection.length);
+ }
+ } catch (Exception e) {
+ UserError.Log.e(TAG, "config error: " + e);
+ }
+ }
+ return null;
+
+ } // end switch
+ } catch (Exception e) {
+ Log.d(TAG, "Got exception: " + e);
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ private static MatrixCursor matrixRow(Object... x) {
+ final String[] columnNames = new String[x.length / 2];
+ final Object[] values = new Object[x.length / 2];
+ for (int i = 0; i < x.length; i += 2) {
+ columnNames[i / 2] = (String) x[i];
+ values[i / 2] = x[i + 1];
+ }
+ try (
+ MatrixCursor cursor = new MatrixCursor(columnNames)) {
+ cursor.addRow(values);
+ return cursor;
+ } catch (Exception e) {
+ Log.d(TAG, "Error with cursor: " + e);
+ }
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getType(@NonNull Uri uri) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
+ if (!enabled()) return null;
+ try {
+ getContext().getContentResolver().notifyChange(uri, null);
+ } catch (Exception e) {
+ Log.e(TAG, "Got exception during insert " + e);
+ }
+ return null;
+ }
+
+ @Override
+ public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {
+ return 0;
+ }
+
+ @Override
+ public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {
+ return 0;
+ }
+
+ private int boolInt(final boolean bool) {
+ return bool ? 1 : 0;
+ }
+
+ private static boolean enabled() {
+ return isNative() || xdrip.getAppContext() != null && getBooleanDefaultFalse("host_content_provider");
+ }
+
+ private static boolean enabledWrite() {
+ return enabled() && (isNative() || getBooleanDefaultFalse("content_provider_write"));
+ }
+
+ public static void ping(String channel) {
+ if (enabled() && channel != null) {
+ if (channel.equals("bg")) {
+ dgCache.clear();
+ graphCache.clear();
+ }
+ xdrip.getAppContext().getContentResolver().insert(Uri.parse("content://" + BuildConfig.APPLICATION_ID + ".contentprovider/" + channel), null);
+ }
+ }
+
+ public static byte[] convertBitmapToPNGByteArray(Bitmap bitmap) {
+ final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
+ return outputStream.toByteArray();
+ }
+
+}
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/services/Ob1G5CollectionService.java b/app/src/main/java/com/eveningoutpost/dexdrip/services/Ob1G5CollectionService.java
index d3c34c176..e66ad5439 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/services/Ob1G5CollectionService.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/services/Ob1G5CollectionService.java
@@ -14,8 +14,10 @@
import static com.eveningoutpost.dexdrip.g5model.Ob1G5StateMachine.pendingCalibration;
import static com.eveningoutpost.dexdrip.g5model.Ob1G5StateMachine.pendingStart;
import static com.eveningoutpost.dexdrip.g5model.Ob1G5StateMachine.pendingStop;
+import static com.eveningoutpost.dexdrip.g5model.Ob1G5StateMachine.shortTxId;
import static com.eveningoutpost.dexdrip.g5model.Ob1G5StateMachine.usingAlt;
import static com.eveningoutpost.dexdrip.models.JoH.emptyString;
+import static com.eveningoutpost.dexdrip.models.JoH.joinBytes;
import static com.eveningoutpost.dexdrip.models.JoH.msSince;
import static com.eveningoutpost.dexdrip.models.JoH.niceTimeScalar;
import static com.eveningoutpost.dexdrip.models.JoH.tolerantHexStringToByteArray;
@@ -46,7 +48,12 @@
import static com.eveningoutpost.dexdrip.utilitymodels.StatusItem.Highlight.NOTICE;
import static com.eveningoutpost.dexdrip.utils.DexCollectionType.DexcomG5;
import static com.eveningoutpost.dexdrip.utils.bt.Subscription.addErrorHandler;
+import static com.eveningoutpost.dexdrip.watch.thinjam.BlueJayEntry.isNative;
import static com.eveningoutpost.dexdrip.xdrip.gs;
+import static com.polidea.rxandroidble2.scan.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
+import static com.polidea.rxandroidble2.scan.ScanSettings.CALLBACK_TYPE_FIRST_MATCH;
+import static com.polidea.rxandroidble2.scan.ScanSettings.SCAN_MODE_BALANCED;
+import static com.polidea.rxandroidble2.scan.ScanSettings.SCAN_MODE_LOW_LATENCY;
import android.annotation.TargetApi;
import android.app.PendingIntent;
@@ -66,7 +73,9 @@
import android.os.ParcelUuid;
import android.os.PowerManager;
import android.preference.PreferenceManager;
+
import androidx.annotation.NonNull;
+
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
@@ -181,7 +190,7 @@ public class Ob1G5CollectionService extends G5BaseService {
public static volatile CalibrationState lastSensorState = null;
public static volatile long lastUsableGlucosePacketTime = 0;
private static volatile String static_connection_state = null;
- private static volatile long static_last_connected = 0;
+ public static volatile long static_last_connected = 0;
@Setter
@Getter
private static long last_transmitter_timestamp = 0;
@@ -229,8 +238,8 @@ public class Ob1G5CollectionService extends G5BaseService {
private static volatile int skippedConnects = 0;
private static final boolean d = false;
- private static final boolean allow_scan_by_mac = false;
- private static boolean use_auto_connect = false;
+ private static volatile boolean allow_scan_by_mac = false;
+ private static volatile boolean use_auto_connect = false;
private static volatile boolean minimize_scanning = false; // set by preference
private static volatile boolean always_scan = false;
private static volatile boolean scan_next_run = true;
@@ -368,7 +377,7 @@ private synchronized void automata() {
connect_to_device(true);
break;
case DISCOVER:
- if ((wear_broadcast && usingAlt()) || specialPairingWorkaround()){
+ if ((wear_broadcast && usingAlt()) || specialPairingWorkaround()) {
msg("Pausing");
UserError.Log.d(TAG, "Pausing for alt: ");
JoH.threadSleep(1000);
@@ -560,11 +569,12 @@ private synchronized void scan_for_device() {
historicalTransmitterMAC = PersistentStore.getString(OB1G5_MACSTORE + transmitterID); // "" if unset
+ boolean macFilter = false;
ScanFilter filter;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && historicalTransmitterMAC.length() > 5 && allow_scan_by_mac) {
- filter = new ScanFilter.Builder()
- .setDeviceAddress(historicalTransmitterMAC)
- .build();
+ filter = new ScanFilter.Builder().setDeviceAddress(historicalTransmitterMAC).build();
+ UserError.Log.d(TAG, "Using mac filter " + historicalTransmitterMAC);
+ macFilter = true;
} else {
final String localTransmitterID = transmitterID;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && localTransmitterID != null && localTransmitterID.length() > 4) {
@@ -581,19 +591,19 @@ private synchronized void scan_for_device() {
}
scanSubscription = new Subscription(rxBleClient.scanBleDevices(
- new ScanSettings.Builder()
- //.setScanMode(static_last_timestamp < 1 ? ScanSettings.SCAN_MODE_LOW_LATENCY : ScanSettings.SCAN_MODE_BALANCED)
- //.setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH)
- .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
- .setScanMode(android_wear ? ScanSettings.SCAN_MODE_BALANCED :
- historicalTransmitterMAC.length() <= 5 ? ScanSettings.SCAN_MODE_LOW_LATENCY :
- minimize_scanning ? ScanSettings.SCAN_MODE_BALANCED : ScanSettings.SCAN_MODE_LOW_LATENCY)
- // .setScanMode(ScanSettings.SCAN_MODE_BALANCED)
- .build(),
-
- // scan filter doesn't work reliable on android sdk 23+
- filter
- )
+ new ScanSettings.Builder()
+ //.setScanMode(static_last_timestamp < 1 ? ScanSettings.SCAN_MODE_LOW_LATENCY : ScanSettings.SCAN_MODE_BALANCED)
+ //.setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH)
+ .setCallbackType(macFilter ? CALLBACK_TYPE_FIRST_MATCH : CALLBACK_TYPE_ALL_MATCHES)
+ .setScanMode(android_wear ? SCAN_MODE_BALANCED :
+ historicalTransmitterMAC.length() <= 5 ? SCAN_MODE_LOW_LATENCY :
+ minimize_scanning ? SCAN_MODE_BALANCED : SCAN_MODE_LOW_LATENCY)
+ // .setScanMode(ScanSettings.SCAN_MODE_BALANCED)
+ .build(),
+
+ // scan filter doesn't work reliable on android sdk 23+
+ filter
+ )
// observe on?
// do unsubscribe?
//.doOnUnsubscribe(this::clearSubscription)
@@ -849,6 +859,27 @@ public static synchronized boolean isDeviceLocallyBonded() {
return false;
}
+ public static boolean immediateBonding() {
+ return Pref.getBooleanDefaultFalse("engineering_ob1_bonding_test") || isNative();
+ }
+
+ public static boolean ignoreBonding() {
+ return Pref.getBooleanDefaultFalse("engineering_ob1_ignore_bonding");
+ }
+
+ private byte[] fwChalCache(boolean prefix) {
+ final long chal = Pref.getLong("engineering_ob1_chal_cache" + (prefix ? "_1" : ""), 0);
+ if (chal != 0 && shortTxId()) {
+ final byte[] bytes = new byte[8];
+ for (int i = 0; i < 8; i++) {
+ bytes[i] = (byte) (chal >> (8 - i - 1) * 8);
+ }
+ return bytes;
+ } else {
+ return new byte[0];
+ }
+ }
+
private synchronized void checkAndEnableBT() {
try {
if (Pref.getBoolean("automatically_turn_bluetooth_on", true)) {
@@ -1119,7 +1150,7 @@ public int onStartCommand(Intent intent, int flags, int startId) {
}
minimize_scanning = Pref.getBooleanDefaultFalse("ob1_minimize_scanning");
-
+ allow_scan_by_mac = Build.VERSION.SDK_INT >= 32 && shortTxId();
automata(); // sequence logic
UserError.Log.d(TAG, "Releasing service start");
@@ -1233,7 +1264,7 @@ private synchronized void onScanResult(final ScanResult bleScanResult) {
transmitterMAC = bleScanResult.getBleDevice().getMacAddress();
transmitterIDmatchingMAC = transmitterID;
if (search_name != null) {
- saveTransmitterMac();
+ saveTransmitterMac();
}
//if (JoH.ratelimit("ob1-g5-scan-to-connect-transition", 3)) {
if (state == SCAN) {
@@ -1255,7 +1286,7 @@ private synchronized void onScanResult(final ScanResult bleScanResult) {
}
public void saveTransmitterMac() {
- UserError.Log.d(TAG,"Saving transmitter mac: " + transmitterID + " = " + transmitterMAC);
+ UserError.Log.d(TAG, "Saving transmitter mac: " + transmitterID + " = " + transmitterMAC);
PersistentStore.cleanupOld(OB1G5_MACSTORE);
PersistentStore.setString(OB1G5_MACSTORE + transmitterID, transmitterMAC);
}
@@ -1516,6 +1547,8 @@ private void onServicesDiscovered(RxBleDeviceServices services) {
JoH.static_toast_long(msg);
} else {
plugin.setPersistence(2, PersistentStore.getBytes(KEKS_ONE + transmitterMAC));
+ if (immediateBonding())
+ needsBonding(!isDeviceLocallyBonded() || ignoreBonding());
try {
for (int i = 1; i < 4; i++) {
plugin.setPersistence(7 + i, tolerantHexStringToByteArray(Pref.getStringDefaultBlank(KEKS + "_p" + i)));
@@ -1533,7 +1566,7 @@ private void onServicesDiscovered(RxBleDeviceServices services) {
}
if (specialPairingWorkaround()) {
- UserError.Log.d(TAG,"Samsung additional delay");
+ UserError.Log.d(TAG, "Samsung additional delay");
Inevitable.task("samsung delay", 1000, () -> changeState(STATE.CHECK_AUTH));
} else {
changeState(STATE.CHECK_AUTH);
@@ -1788,7 +1821,7 @@ public static void processCalibrationStateLite(final CalibrationState state, fin
}
}
- public static boolean processCalibrationStateLite(final CalibrationState state) {
+ public static boolean processCalibrationStateLite(final CalibrationState state) {
if (state == CalibrationState.Unknown) {
UserError.Log.d(TAG, "Not processing push of unknown state as this is the unset state");
return false;
@@ -2064,6 +2097,10 @@ void setPurdah(final long duration) {
}
}
+ void needsBonding(final boolean required) {
+ plugin.setPersistence(6, joinBytes(new byte[]{(byte) ((required ? 0 : 1) << 1)}, fwChalCache(required)));
+ }
+
private static void handleUnknownFirmwareClick() {
UserError.Log.d(TAG, "handleUnknownFirmwareClick()");
if (UpdateActivity.testAndSetNightly(true)) {
@@ -2306,9 +2343,9 @@ public void run() {
l.add(new StatusItem("Voltage A", parsedBattery.voltageA(), parsedBattery.voltageAWarning() ? BAD : NORMAL));
l.add(new StatusItem("Voltage B", parsedBattery.voltageB(), parsedBattery.voltageBWarning() ? BAD : NORMAL));
if (vr != null && FirmwareCapability.isFirmwareResistanceCapable(vr.firmware_version_string)) {
- if (parsedBattery.resistance() != 0) {
- l.add(new StatusItem("Resistance", parsedBattery.resistance(), parsedBattery.resistanceStatus().highlight));
- }
+ if (parsedBattery.resistance() != 0) {
+ l.add(new StatusItem("Resistance", parsedBattery.resistance(), parsedBattery.resistanceStatus().highlight));
+ }
}
if (vr != null && FirmwareCapability.isFirmwareTemperatureCapable(vr.firmware_version_string)) {
if (parsedBattery.temperature() > 0) {
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/tables/BgReadingTable.java b/app/src/main/java/com/eveningoutpost/dexdrip/tables/BgReadingTable.java
index 7639d7f2d..a3ffaa759 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/tables/BgReadingTable.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/tables/BgReadingTable.java
@@ -5,7 +5,9 @@
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;
+
import androidx.drawerlayout.widget.DrawerLayout;
+
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -19,14 +21,19 @@
import com.eveningoutpost.dexdrip.NavigationDrawerFragment;
import com.eveningoutpost.dexdrip.R;
import com.eveningoutpost.dexdrip.utilitymodels.BgGraphBuilder;
+import com.eveningoutpost.dexdrip.utilitymodels.Constants;
import com.eveningoutpost.dexdrip.utilitymodels.Pref;
+import com.eveningoutpost.dexdrip.utils.DexCollectionType;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import java.util.Locale;
import static com.eveningoutpost.dexdrip.xdrip.gs;
+import lombok.val;
+
public class BgReadingTable extends BaseListActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks {
private String menu_name = "BG Data Table";
@@ -55,9 +62,39 @@ public void onNavigationDrawerItemSelected(int position) {
private void getData() {
final List latest = BgReading.latest(5000);
+ parseDataForStats(latest);
ListAdapter adapter = new BgReadingAdapter(this, latest);
-
this.setListAdapter(adapter);
+ try {
+ if (total > 0) {
+ this.getActionBar().setSubtitle(String.format(Locale.getDefault(), "%d in 24h, bf:%d%% mis:%d", total, ((backfilled * 100) / total), missing));
+ }
+ } catch (NullPointerException e) {
+ //
+ }
+ }
+
+ private int missing;
+ private int backfilled;
+ private int total;
+
+ private void parseDataForStats(List list) {
+ long cutoff = JoH.tsl() - Constants.DAY_IN_MS;
+ long oldest = 0;
+ for (val item : list) {
+ if (item.timestamp < cutoff) break;
+ oldest = item.timestamp;
+ total++;
+ if (item.source_info != null && item.source_info.contains("Backfill")) {
+ backfilled++;
+ }
+ }
+
+ if (total > 0) {
+ val expectedReadings = (JoH.tsl() - oldest) / DexCollectionType.getCurrentSamplePeriod();
+ missing = (int) (expectedReadings - total);
+ }
+
}
public static class BgReadingCursorAdapterViewHolder {
@@ -75,12 +112,12 @@ public BgReadingCursorAdapterViewHolder(View root) {
}
public static class BgReadingAdapter extends BaseAdapter {
- private final Context context;
+ private final Context context;
private final List readings;
public BgReadingAdapter(Context context, List readings) {
this.context = context;
- if(readings == null)
+ if (readings == null)
readings = new ArrayList<>();
this.readings = readings;
@@ -119,19 +156,21 @@ public boolean onLongClick(View v) {
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- switch (which){
+ switch (which) {
case DialogInterface.BUTTON_POSITIVE:
bgReading.ignoreForStats = true;
bgReading.save();
notifyDataSetChanged();
- if (Pref.getBooleanDefaultFalse("wear_sync")) BgReading.pushBgReadingSyncToWatch(bgReading, false);
+ if (Pref.getBooleanDefaultFalse("wear_sync"))
+ BgReading.pushBgReadingSyncToWatch(bgReading, false);
break;
case DialogInterface.BUTTON_NEGATIVE:
bgReading.ignoreForStats = false;
bgReading.save();
notifyDataSetChanged();
- if (Pref.getBooleanDefaultFalse("wear_sync")) BgReading.pushBgReadingSyncToWatch(bgReading, false);
+ if (Pref.getBooleanDefaultFalse("wear_sync"))
+ BgReading.pushBgReadingSyncToWatch(bgReading, false);
break;
}
}
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/AlertPlayer.java b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/AlertPlayer.java
index 5a168db92..6380d824e 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/AlertPlayer.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/AlertPlayer.java
@@ -4,6 +4,7 @@
import static com.eveningoutpost.dexdrip.models.JoH.delayedMediaPlayerRelease;
import static com.eveningoutpost.dexdrip.models.JoH.setMediaDataSource;
import static com.eveningoutpost.dexdrip.models.JoH.stopAndReleasePlayer;
+import static com.eveningoutpost.dexdrip.receiver.InfoContentProvider.ping;
import android.app.Notification;
import android.app.NotificationManager;
@@ -188,6 +189,7 @@ public synchronized void startAlert(Context ctx, boolean trendingToAlertEnd, Al
ActiveBgAlert.Create(newAlert.uuid, start_snoozed, nextAlertTime);
if (!start_snoozed) VibrateNotifyMakeNoise(ctx, newAlert, bgValue, 0);
+ ping("alarm");
AlertTracker.evaluate();
}
@@ -213,6 +215,7 @@ public synchronized void stopAlert(Context ctx, boolean ClearData, boolean clear
}
revertCurrentVolume(streamType);
releaseAudioFocus();
+ ping("alarm");
}
// only do something if an alert is active - only call from interactive
@@ -246,6 +249,7 @@ public synchronized void Snooze(Context ctx, int repeatTime) {
}
BroadcastEntry.cancelAlert();
+ ping("alarm");
}
public synchronized void Snooze(Context ctx, int repeatTime, boolean from_interactive) {
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 2a89e319e..8f5de0272 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/CollectionServiceStarter.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/CollectionServiceStarter.java
@@ -510,7 +510,7 @@ private void startServiceCompat(final Class service) {
@SuppressWarnings("ConstantConditions")
private void startServiceCompat(final Intent intent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
- && BuildConfig.targetSDK >= Build.VERSION_CODES.N
+ // && BuildConfig.targetSDK >= Build.VERSION_CODES.N
&& ForegroundServiceStarter.shouldRunCollectorInForeground()) {
try {
Log.d(TAG, String.format("Starting oreo foreground service: %s", intent.getComponent().getClassName()));
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/ColorCache.java b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/ColorCache.java
index f11bb521b..aca930945 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/ColorCache.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/ColorCache.java
@@ -26,17 +26,23 @@ public static void invalidateCache() {
}
public static int getCol(final X color) {
- if (!the_cache.containsKey(color)) {
- try {
- the_cache.put(color, Pref.getInt(color.internalName, 0xABCDEF));
- } catch (ClassCastException e) {
- UserError.Log.wtf(TAG, "Cannot set initial value - preference type likely wrong for: " + color.internalName + " " + e);
- the_cache.put(color, Color.GRAY);
+
+ if (!the_cache.containsKey(color)) {
+ try {
+ the_cache.put(color, Pref.getInt(color.internalName, 0xABCDEF));
+ } catch (ClassCastException e) {
+ UserError.Log.wtf(TAG, "Cannot set initial value - preference type likely wrong for: " + color.internalName + " " + e);
+ the_cache.put(color, Color.GRAY);
+ }
+ if (debug)
+ UserError.Log.d(TAG, "Setting cache for color: " + color.internalName + " / " + Pref.getInt(color.internalName, 1234));
}
- if (debug)
- UserError.Log.d(TAG, "Setting cache for color: " + color.internalName + " / " + Pref.getInt(color.internalName, 1234));
- }
- return the_cache.get(color);
+ int col = the_cache.get(color);
+ if (col == 0xABCDEF && color.internalName.equals("color_low_values")) {
+ the_cache.clear(); // preferences init hasn't run yet as is local default
+ }
+ return col;
+
}
public enum X {
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/InstalledApps.java b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/InstalledApps.java
index 8be5bd1b7..6e4cc5898 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/InstalledApps.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/InstalledApps.java
@@ -1,5 +1,7 @@
package com.eveningoutpost.dexdrip.utilitymodels;
+import static com.eveningoutpost.dexdrip.watch.thinjam.BlueJayEntry.isNative;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -23,7 +25,7 @@ public class InstalledApps {
private static final String GOOGLE_PLAY_SERVICES_PACKAGE = "com.google.android.gms";
public static boolean isGooglePlayInstalled(Context context) {
- return checkPackageExists(context, GOOGLE_PLAY_SERVICES_PACKAGE);
+ return isNative() || checkPackageExists(context, GOOGLE_PLAY_SERVICES_PACKAGE);
}
public static boolean checkPackageExists(Context context, String packageName) {
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/Pref.java b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/Pref.java
index c6bc342ef..d7aa09301 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/Pref.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/Pref.java
@@ -30,7 +30,11 @@ private static void initializePrefs() {
}
} else {
if (JoH.ratelimit("prefs-failure2", 20)) {
- UserError.Log.wtf(TAG, "Could not initialize preferences due to missing context!!");
+ try {
+ UserError.Log.wtf(TAG, "Could not initialize preferences due to missing context!!");
+ } catch (NullPointerException e) {
+ android.util.Log.wtf(TAG, "Could not initialize preferences due to missing context and then got null pointer!!");
+ }
}
}
}
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/SendFeedBack.java b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/SendFeedBack.java
index fa1750d96..7f0538590 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/SendFeedBack.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/SendFeedBack.java
@@ -16,6 +16,7 @@
import com.eveningoutpost.dexdrip.BaseAppCompatActivity;
import com.eveningoutpost.dexdrip.models.JoH;
import com.eveningoutpost.dexdrip.R;
+import com.eveningoutpost.dexdrip.watch.thinjam.BlueJayEntry;
import com.squareup.okhttp.FormEncodingBuilder;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.MediaType;
@@ -33,6 +34,7 @@
import okio.Okio;
import static com.eveningoutpost.dexdrip.utils.DexCollectionType.getBestCollectorHardwareName;
+import static com.eveningoutpost.dexdrip.watch.thinjam.BlueJayEntry.isNative;
import androidx.appcompat.app.AlertDialog;
@@ -54,7 +56,7 @@ public class SendFeedBack extends BaseAppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_send_feed_back);
- send_url = getString(R.string.wserviceurl) + "/joh-feedback";
+ send_url = getString(isNative() ? R.string.qserviceurl : R.string.wserviceurl) + "/joh-feedback";
myrating = (RatingBar) findViewById(R.id.ratingBar);
ratingtext = (TextView) findViewById(R.id.ratingtext);
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/SourceWizard.java b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/SourceWizard.java
index 703f4defe..96f13f5e1 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/SourceWizard.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/SourceWizard.java
@@ -87,7 +87,7 @@ public static void start(Activity activity) {
}
public synchronized static void start(Activity activity, boolean force) {
- if (sw == null) sw = new SourceWizard(activity);
+ if (sw == null || sw.activity != activity) sw = new SourceWizard(activity);
if (force) {
if (sw.showing()) sw.dismiss();
}
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/VoiceCommands.java b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/VoiceCommands.java
index 6f1138b2b..977a82fe7 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/VoiceCommands.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/utilitymodels/VoiceCommands.java
@@ -197,6 +197,8 @@ public static void processVoiceCommand(final String allWords, final Activity mAc
case "database administration":
JoH.startActivity(DatabaseAdmin.class);
break;
+ case "simulate crash":
+ throw new RuntimeException("Test crash");
}
}
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/utils/BlobCache.java b/app/src/main/java/com/eveningoutpost/dexdrip/utils/BlobCache.java
new file mode 100644
index 000000000..7d2ae2e14
--- /dev/null
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/utils/BlobCache.java
@@ -0,0 +1,66 @@
+package com.eveningoutpost.dexdrip.utils;
+
+import android.os.SystemClock;
+
+// JamOrHam
+public class BlobCache {
+
+ private final Object lock = new Object();
+ private volatile Object blobCache = null;
+ private static volatile long blobTime = 0;
+ static volatile long blobParamX = 0;
+ static volatile long blobParamY = 0;
+
+ private final long timeout;
+
+ public BlobCache(long timeout) {
+ this.timeout = timeout;
+ }
+
+ public void set(Object o) {
+ synchronized (lock) {
+ blobCache = o;
+ blobTime = SystemClock.elapsedRealtime();
+ }
+ }
+
+ public Object get() {
+ synchronized (lock) {
+ if (isExpired()) {
+ blobCache = null;
+ }
+ return blobCache;
+ }
+ }
+
+ public void set(Object o, long x, long y) {
+ synchronized (lock) {
+ blobParamX = x;
+ blobParamY = y;
+ blobCache = o;
+ blobTime = SystemClock.elapsedRealtime();
+ }
+ }
+
+ public Object get(long x, long y) {
+ synchronized (lock) {
+ if (x != blobParamX || y != blobParamY) {
+ return null;
+ }
+ return get();
+ }
+ }
+
+ public void clear() {
+ blobCache = null;
+ blobTime = 0;
+ }
+
+ public boolean isExpired() {
+ synchronized (lock) {
+ return (blobCache == null || SystemClock.elapsedRealtime() - blobTime > timeout);
+ }
+ }
+
+}
+
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/utils/Preferences.java b/app/src/main/java/com/eveningoutpost/dexdrip/utils/Preferences.java
index 8db254ccb..afbb490e9 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/utils/Preferences.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/utils/Preferences.java
@@ -79,6 +79,7 @@
import com.eveningoutpost.dexdrip.models.UserNotification;
import com.eveningoutpost.dexdrip.plugin.Dialog;
import com.eveningoutpost.dexdrip.profileeditor.ProfileEditor;
+import com.eveningoutpost.dexdrip.receiver.InfoContentProvider;
import com.eveningoutpost.dexdrip.services.ActivityRecognizedService;
import com.eveningoutpost.dexdrip.services.BluetoothGlucoseMeter;
import com.eveningoutpost.dexdrip.services.DexCollectionService;
@@ -299,6 +300,7 @@ private void installxDripPlusPreferencesFromQRCode(SharedPreferences prefs, Stri
Toast.makeText(getApplicationContext(), "Loaded " + Integer.toString(changes) + " preferences from QR code", Toast.LENGTH_LONG).show();
PlusSyncService.clearandRestartSyncService(getApplicationContext());
DesertSync.settingsChanged(); // refresh
+ InfoContentProvider.ping("pref");
if (prefs.getString("dex_collection_method", "").equals("Follower")) {
PlusSyncService.clearandRestartSyncService(getApplicationContext());
GcmActivity.last_sync_request = 0;
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/utils/SdcardImportExport.java b/app/src/main/java/com/eveningoutpost/dexdrip/utils/SdcardImportExport.java
index afcfcbaed..6b527a858 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/utils/SdcardImportExport.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/utils/SdcardImportExport.java
@@ -31,6 +31,7 @@
import java.util.ArrayList;
import java.util.List;
+import static com.eveningoutpost.dexdrip.receiver.InfoContentProvider.ping;
import static com.eveningoutpost.dexdrip.utils.FileUtils.getExternalDir;
@@ -162,6 +163,7 @@ public void loadPreferencesToSD(View myview) {
public static void storePreferencesFromBytes(byte[] bytes, Context context) {
if (dataFromBytes(bytes, PREFERENCES_FILE, context)) {
+ ping("pref");
Log.i(TAG, "Restarting as new preferences loaded from bytes");
hardReset();
} else {
@@ -291,6 +293,7 @@ public static void restoreSettingsNow(Activity activity) {
JoH.static_toast_long("Restoring Settings");
if (copyPreferencesFileBack(activity, results.get(0))) {
Log.e(TAG, "Restoring preferences succeeded from first match: " + results.get(0));
+ ping("pref");
hardReset();
} else {
JoH.static_toast_long("Couldn't restore preferences from: " + results.get(0));
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/utils/framework/WakeLockTrampoline.java b/app/src/main/java/com/eveningoutpost/dexdrip/utils/framework/WakeLockTrampoline.java
index fea5f5e36..1c34b46c5 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/utils/framework/WakeLockTrampoline.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/utils/framework/WakeLockTrampoline.java
@@ -64,7 +64,7 @@ public void onReceive(final Context context, final Intent broadcastIntent) {
ComponentName startResult;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
- && BuildConfig.targetSDK >= Build.VERSION_CODES.N
+ // && BuildConfig.targetSDK >= Build.VERSION_CODES.N
&& ForegroundServiceStarter.shouldRunCollectorInForeground()) {
try {
UserError.Log.d(TAG, String.format("Starting oreo foreground service: %s", serviceIntent.getComponent().getClassName()));
diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/watch/thinjam/BlueJayEntry.java b/app/src/main/java/com/eveningoutpost/dexdrip/watch/thinjam/BlueJayEntry.java
index 2c0584307..053c4dbf0 100644
--- a/app/src/main/java/com/eveningoutpost/dexdrip/watch/thinjam/BlueJayEntry.java
+++ b/app/src/main/java/com/eveningoutpost/dexdrip/watch/thinjam/BlueJayEntry.java
@@ -1,6 +1,7 @@
package com.eveningoutpost.dexdrip.watch.thinjam;
import android.content.SharedPreferences;
+import android.os.Build;
import com.eveningoutpost.dexdrip.models.JoH;
import com.eveningoutpost.dexdrip.utilitymodels.CollectionServiceStarter;
@@ -124,6 +125,10 @@ public static void sendPngIfEnabled(final byte[] bytes, final String parameters,
}
}
+ public static boolean isNative() {
+ return Build.MODEL.startsWith("BlueJay U");
+ }
+
static void startWithRefresh() {
Inevitable.task("bluejay-preference-changed", 1000, () -> JoH.startService(BlueJayService.class, "function", "refresh"));
}
diff --git a/app/src/main/res/values/internal.xml b/app/src/main/res/values/internal.xml
index 554a572aa..bc7838a5e 100644
--- a/app/src/main/res/values/internal.xml
+++ b/app/src/main/res/values/internal.xml
@@ -27,6 +27,7 @@
xDrip+
xDrip+
https://xdrip-plus-updates.appspot.com
+ https://xdrip-plus-updates.cflare-509.workers.dev
all_settings_wizard
wizard_uuid
wizard_key
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index b5b4139d1..a55737e4d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1902,4 +1902,5 @@
Pause all other sounds
Use Camera Light
Flash camera light during alerts when connected to a charger
+ G7 should start automatically
diff --git a/libkeks/src/main/java/jamorham/keks/Plugin.java b/libkeks/src/main/java/jamorham/keks/Plugin.java
index 8237942fb..6b849b4a7 100644
--- a/libkeks/src/main/java/jamorham/keks/Plugin.java
+++ b/libkeks/src/main/java/jamorham/keks/Plugin.java
@@ -121,6 +121,7 @@ private static String stateToName(final int state) {
private volatile AuthRequestTxMessage2 lastAuthTx2;
private volatile int state = 0;
private volatile byte[] accumulator = new byte[0];
+ private volatile byte[] newFwchal = new byte[0];
private volatile byte[] keyToTestAgainst = null;
static {
@@ -336,7 +337,7 @@ public boolean receivedResponse3(byte[] data) {
private boolean alt = false;
private AuthRequestTxMessage2 getAuthRequestTx2() {
- lastAuthTx2 = new AuthRequestTxMessage2(8, alt);
+ lastAuthTx2 = new AuthRequestTxMessage2(8, alt, newFwchal);
return lastAuthTx2;
}
@@ -480,6 +481,7 @@ public boolean setPersistence(int channel, byte[] data) {
}
if (channel == 6) {
alt = Arrays.equals(data, SPARAM.bytes);
+ newFwchal = data;
}
if (channel == 7) {
dontClearAccumulator.clear();
diff --git a/libkeks/src/main/java/jamorham/keks/message/AuthRequestTxMessage2.java b/libkeks/src/main/java/jamorham/keks/message/AuthRequestTxMessage2.java
index ec4dfa862..d635f00bd 100644
--- a/libkeks/src/main/java/jamorham/keks/message/AuthRequestTxMessage2.java
+++ b/libkeks/src/main/java/jamorham/keks/message/AuthRequestTxMessage2.java
@@ -17,11 +17,12 @@ public class AuthRequestTxMessage2 extends BaseMessage {
private static final byte endByteAlt = 0x1;
public AuthRequestTxMessage2(int token_size) {
- this(token_size, false);
+ this(token_size, false, new byte[0]);
}
- public AuthRequestTxMessage2(int token_size, boolean alt) {
- this(token_size, alt ? endByteAlt : endByteStd);
+ public AuthRequestTxMessage2(int token_size, boolean alt, byte[] chal) {
+ this(token_size, (alt ? endByteAlt : endByteStd)
+ + (chal.length > 2 ? chal[2] : 0));
}
public AuthRequestTxMessage2(int token_size, int slot) {