diff --git a/app/src/main/assets/OpenAPSMA/determine-basal.js b/app/src/main/assets/OpenAPSMA/determine-basal.js deleted file mode 100644 index 4c5a00fade..0000000000 --- a/app/src/main/assets/OpenAPSMA/determine-basal.js +++ /dev/null @@ -1,316 +0,0 @@ -/* - Determine Basal - - Released under MIT license. See the accompanying LICENSE.txt file for - full terms and conditions - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ -var determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, offline, meal_data, setTempBasal) { - var rT = { //short for requestedTemp - }; - - if (typeof profile === 'undefined' || typeof profile.current_basal === 'undefined') { - rT.error ='Error: could not get current basal rate'; - return rT; - } - - var bg = glucose_status.glucose; - if (bg < 38) { //Dexcom is in ??? mode or calibrating, do nothing. Asked @benwest for raw data in iter_glucose - rT.error = "CGM is calibrating or in ??? state"; - return rT; - } - - var max_iob = profile.max_iob; // maximum amount of non-bolus IOB OpenAPS will ever deliver - - // if target_bg is set, great. otherwise, if min and max are set, then set target to their average - var target_bg; - if (typeof profile.target_bg !== 'undefined') { - target_bg = profile.target_bg; - } else { - if (typeof profile.min_bg !== 'undefined' && typeof profile.max_bg !== 'undefined') { - target_bg = (profile.min_bg + profile.max_bg) / 2; - } else { - rT.error ='Error: could not determine target_bg'; - return rT; - } - } - - - if (typeof iob_data === 'undefined' ) { - rT.error ='Error: iob_data undefined'; - return rT; - } - - if (typeof iob_data.activity === 'undefined' || typeof iob_data.iob === 'undefined' || typeof iob_data.activity === 'undefined') { - rT.error ='Error: iob_data missing some property'; - return rT; - } - - var tick; - - if (glucose_status.delta >= 0) { - tick = "+" + glucose_status.delta; - } else { - tick = glucose_status.delta; - } - var minDelta = Math.min(glucose_status.delta, glucose_status.avgdelta); - //var maxDelta = Math.max(glucose_status.delta, glucose_status.avgdelta); - - - //calculate BG impact: the amount BG "should" be rising or falling based on insulin activity alone - var bgi = Math.round(( -iob_data.activity * profile.sens * 5 )*100)/100; - // project positive deviations for 15 minutes - var deviation = Math.round( 15 / 5 * ( glucose_status.avgdelta - bgi ) ); - // project negative deviations for 30 minutes - if (deviation < 0) { - deviation = Math.round( 30 / 5 * ( glucose_status.avgdelta - bgi ) ); - } - //console.log("Avg.Delta: " + glucose_status.avgdelta.toFixed(1) + ", BGI: " + bgi.toFixed(1) + " 15m activity projection: " + deviation.toFixed(0)); - - // calculate the naive (bolus calculator math) eventual BG based on net IOB and sensitivity - var naive_eventualBG = Math.round( bg - (iob_data.iob * profile.sens) ); - // and adjust it for the deviation above - var eventualBG = naive_eventualBG + deviation; - // calculate what portion of that is due to bolussnooze - var bolusContrib = iob_data.bolussnooze * profile.sens; - // and add it back in to get snoozeBG, plus another 50% to avoid low-temping at mealtime - var naive_snoozeBG = Math.round( naive_eventualBG + 1.5 * bolusContrib ); - // adjust that for deviation like we did eventualBG - var snoozeBG = naive_snoozeBG + deviation; - - //console.log("BG: " + bg +"(" + tick + ","+glucose_status.avgdelta.toFixed(1)+")"+ " -> " + eventualBG + "-" + snoozeBG + " (Unadjusted: " + naive_eventualBG + "-" + naive_snoozeBG + "), BGI: " + bgi); - - var expectedDelta = Math.round(( bgi + ( target_bg - eventualBG ) / ( profile.dia * 60 / 5 ) )*10)/10; - //console.log("expectedDelta: " + expectedDelta); - - if (typeof eventualBG === 'undefined' || isNaN(eventualBG)) { - rT.error ='Error: could not calculate eventualBG'; - return rT; - } - - // min_bg of 90 -> threshold of 70, 110 -> 80, and 130 -> 90 - var threshold = profile.min_bg - 0.5*(profile.min_bg-50); - - rT = { - 'temp': 'absolute' - , 'bg': bg - , 'tick': tick - , 'eventualBG': eventualBG - , 'snoozeBG': snoozeBG - }; - - var basaliob; - if (iob_data.basaliob) { basaliob = iob_data.basaliob; } - else { basaliob = iob_data.iob - iob_data.bolussnooze; } - // allow meal assist to run when carbs are just barely covered - if (minDelta > Math.max(3, bgi) && ( (meal_data.carbs > 0 && (1.1 * meal_data.carbs/profile.carb_ratio > meal_data.boluses + basaliob)) || ( deviation > 25 && minDelta > 7 ) ) ) { - // ignore all covered IOB, and just set eventualBG to the current bg - eventualBG = Math.max(bg,eventualBG) + deviation; - rT.eventualBG = eventualBG; - profile.min_bg = 80; - target_bg = (profile.min_bg + profile.max_bg) / 2; - expectedDelta = Math.round(( bgi + ( target_bg - eventualBG ) / ( profile.dia * 60 / 5 ) )*10)/10; - rT.mealAssist = "On: Carbs: " + meal_data.carbs + " Boluses: " + meal_data.boluses + " Target: " + target_bg + " Deviation: " + deviation + " BGI: " + bgi; - } else { - rT.mealAssist = "Off: Carbs: " + meal_data.carbs + " Boluses: " + meal_data.boluses + " Target: " + target_bg + " Deviation: " + deviation + " BGI: " + bgi; - } - if (bg < threshold) { // low glucose suspend mode: BG is < ~80 - rT.reason = "BG " + bg + "<" + threshold; - if ((glucose_status.delta <= 0 && glucose_status.avgdelta <= 0) || (glucose_status.delta < expectedDelta && glucose_status.avgdelta < expectedDelta)) { - // BG is still falling / rising slower than predicted - return setTempBasal(0, 30, profile, rT, offline); - } - if (glucose_status.delta > glucose_status.avgdelta) { - rT.reason += ", delta " + glucose_status.delta + ">0"; - } else { - rT.reason += ", avg delta " + glucose_status.avgdelta.toFixed(2) + ">0"; - } - if (currenttemp.rate > profile.current_basal) { // if a high-temp is running - rT.reason += ", cancel high temp"; - return setTempBasal(0, 0, profile, rT, offline); // cancel high temp - } else if (currenttemp.duration && eventualBG > profile.max_bg) { // if low-temped and predicted to go high from negative IOB - rT.reason += ", cancel low temp"; - return setTempBasal(0, 0, profile, rT, offline); // cancel low temp - } - rT.reason += "; no high-temp to cancel"; - return rT; - } - if (eventualBG < profile.min_bg) { // if eventual BG is below target: - if (rT.mealAssist.indexOf("On") == 0) { - rT.reason = "Meal assist: " + meal_data.carbs + "g, " + meal_data.boluses + "U"; - } else { - rT.reason = "Eventual BG " + eventualBG + "<" + profile.min_bg; - // if 5m or 15m avg BG is rising faster than expected delta - if (minDelta > expectedDelta && minDelta > 0) { - if (glucose_status.delta > glucose_status.avgdelta) { - rT.reason += ", but Delta " + tick + " > Exp. Delta " + expectedDelta; - } else { - rT.reason += ", but Avg. Delta " + glucose_status.avgdelta.toFixed(2) + " > Exp. Delta " + expectedDelta; - } - if (currenttemp.duration > 0) { // if there is currently any temp basal running - rT.reason = rT.reason += "; cancel"; - return setTempBasal(0, 0, profile, rT, offline); // cancel temp - } else { - rT.reason = rT.reason += "; no temp to cancel"; - return rT; - } - } - } - - if (eventualBG < profile.min_bg) { - // if this is just due to boluses, we can snooze until the bolus IOB decays (at double speed) - if (snoozeBG > profile.min_bg) { // if adding back in the bolus contribution BG would be above min - // if BG is falling and high-temped, or rising and low-temped, cancel - // compare against zero here, not BGI, because BGI will be highly negative from boluses and no carbs - if (glucose_status.delta < 0 && currenttemp.duration > 0 && currenttemp.rate > profile.current_basal) { - rT.reason += tick + ", and temp " + currenttemp.rate + " > basal " + profile.current_basal; - return setTempBasal(0, 0, profile, rT, offline); // cancel temp - } else if (glucose_status.delta > 0 && currenttemp.duration > 0 && currenttemp.rate < profile.current_basal) { - rT.reason += tick + ", and temp " + currenttemp.rate + " < basal " + profile.current_basal; - return setTempBasal(0, 0, profile, rT, offline); // cancel temp - } - - rT.reason += ", bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; - return rT; - } else { - // calculate 30m low-temp required to get projected BG up to target - // use snoozeBG to more gradually ramp in any counteraction of the user's boluses - // multiply by 2 to low-temp faster for increased hypo safety - var insulinReq = 2 * Math.min(0, (snoozeBG - target_bg) / profile.sens); - if (minDelta < 0 && minDelta > expectedDelta) { - // if we're barely falling, newinsulinReq should be barely negative - rT.reason += ", Snooze BG " + snoozeBG; - var newinsulinReq = Math.round(( insulinReq * (minDelta / expectedDelta) ) * 100)/100; - //console.log("Increasing insulinReq from " + insulinReq + " to " + newinsulinReq); - insulinReq = newinsulinReq; - } - // rate required to deliver insulinReq less insulin over 30m: - var rate = profile.current_basal + (2 * insulinReq); - rate = Math.round( rate * 1000 ) / 1000; - // if required temp < existing temp basal - var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile.current_basal) / 60; - if (insulinScheduled < insulinReq - 0.2) { // if current temp would deliver >0.2U less than the required insulin, raise the rate - rT.reason = currenttemp.duration + "m@" + (currenttemp.rate - profile.current_basal).toFixed(3) + " = " + insulinScheduled.toFixed(3) + " < req " + insulinReq + "-0.2U"; - return setTempBasal(rate, 30, profile, rT, offline); - } - if (typeof currenttemp.rate !== 'undefined' && (currenttemp.duration > 5 && rate > currenttemp.rate - 0.1)) { - rT.reason += ", temp " + currenttemp.rate + " ~< req " + rate + "U/hr"; - return rT; - } else { - rT.reason += ", setting " + rate + "U/hr"; - return setTempBasal(rate, 30, profile, rT, offline); - } - } - } - } - - // if eventual BG is above min but BG is falling faster than expected Delta - if (minDelta < expectedDelta) { - if (glucose_status.delta < glucose_status.avgdelta) { - rT.reason = "Eventual BG " + eventualBG + ">" + profile.min_bg + " but Delta " + tick + " < Exp. Delta " + expectedDelta; - } else { - rT.reason = "Eventual BG " + eventualBG + ">" + profile.min_bg + " but Avg. Delta " + glucose_status.avgdelta.toFixed(2) + " < Exp. Delta " + expectedDelta; - } - if (currenttemp.duration > 0) { // if there is currently any temp basal running - rT.reason = rT.reason += "; cancel"; - return setTempBasal(0, 0, profile, rT, offline); // cancel temp - } else { - rT.reason = rT.reason += "; no temp to cancel"; - return rT; - } - } - - if (eventualBG < profile.max_bg) { - rT.reason = eventualBG + " is in range. No temp required"; - if (currenttemp.duration > 0) { // if there is currently any temp basal running - rT.reason = rT.reason += "; cancel"; - return setTempBasal(0, 0, profile, rT, offline); // cancel temp - } - if (offline == 'Offline') { - // if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working - if ((!currenttemp.duration || (currenttemp.rate == profile.current_basal)) && !rT.duration) { - rT.reason = rT.reason + "; setting current basal of " + profile.current_basal + " as temp"; - return setTempBasal(profile.current_basal, 30, profile, rT, offline); - } - } - return rT; - } - - if (snoozeBG < profile.max_bg) { - rT.reason = snoozeBG + " < " + profile.max_bg; - if (currenttemp.duration > 0) { // if there is currently any temp basal running - rT.reason = rT.reason += "; cancel"; - return setTempBasal(0, 0, profile, rT, offline); // cancel temp - } else { - rT.reason = rT.reason += "; no temp to cancel"; - return rT; - } - } - - - // eventual BG is at/above target: - // if iob is over max, just cancel any temps - var basaliob; - if (iob_data.basaliob) { basaliob = iob_data.basaliob; } - else { basaliob = iob_data.iob - iob_data.bolussnooze; } - rT.reason = "Eventual BG " + eventualBG + ">=" + profile.max_bg + ", "; - if (basaliob > max_iob) { - rT.reason = "basaliob " + basaliob + " > max_iob " + max_iob; - return setTempBasal(0, 0, profile, rT, offline); - } else { // otherwise, calculate 30m high-temp required to get projected BG down to target - - // insulinReq is the additional insulin required to get down to max bg: - // if in meal assist mode, check if snoozeBG is lower, as eventualBG is not dependent on IOB - var insulinReq = (Math.min(snoozeBG,eventualBG) - target_bg) / profile.sens; - if (minDelta < 0 && minDelta > expectedDelta) { - var newinsulinReq = Math.round(( insulinReq * (1 - (minDelta / expectedDelta)) ) * 100)/100; - //console.log("Reducing insulinReq from " + insulinReq + " to " + newinsulinReq); - insulinReq = newinsulinReq; - } - // if that would put us over max_iob, then reduce accordingly - if (insulinReq > max_iob-basaliob) { - rT.reason = "max_iob " + max_iob + ", "; - insulinReq = max_iob-basaliob; - } - - // rate required to deliver insulinReq more insulin over 30m: - var rate = profile.current_basal + (2 * insulinReq); - rate = Math.round( rate * 1000 ) / 1000; - - var maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); - if (rate > maxSafeBasal) { - rT.reason += "adj. req. rate:"+rate.toFixed(1) +" to maxSafeBasal:"+maxSafeBasal.toFixed(1)+", "; - rate = maxSafeBasal; - } - - var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile.current_basal) / 60; - if (insulinScheduled > insulinReq + 0.2) { // if current temp would deliver >0.2U more than the required insulin, lower the rate - rT.reason = currenttemp.duration + "m@" + (currenttemp.rate - profile.current_basal).toFixed(3) + " = " + insulinScheduled.toFixed(3) + " > req " + insulinReq + "+0.2U"; - return setTempBasal(rate, 30, profile, rT, offline); - } - - if (typeof currenttemp.duration == 'undefined' || currenttemp.duration == 0) { // no temp is set - rT.reason += "no temp, setting " + rate + "U/hr"; - return setTempBasal(rate, 30, profile, rT, offline); - } - - if (currenttemp.duration > 5 && rate < currenttemp.rate + 0.1) { // if required temp <~ existing temp basal - rT.reason += "temp " + currenttemp.rate + " >~ req " + rate + "U/hr"; - return rT; - } - - // required temp > existing temp basal - rT.reason += "temp " + currenttemp.rate + "<" + rate + "U/hr"; - return setTempBasal(rate, 30, profile, rT, offline); - } - -}; - -module.exports = determine_basal; \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt b/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt index 187ab7b33d..8af3f486c5 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/MyPreferenceFragment.kt @@ -19,7 +19,6 @@ import info.nightscout.androidaps.events.EventRebuildTabs import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin -import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.PluginStore @@ -80,7 +79,6 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang @Inject lateinit var medtronicPumpPlugin: MedtronicPumpPlugin @Inject lateinit var nsClientPlugin: NSClientPlugin @Inject lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin - @Inject lateinit var openAPSMAPlugin: OpenAPSMAPlugin @Inject lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin @Inject lateinit var safetyPlugin: SafetyPlugin @Inject lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin @@ -162,7 +160,6 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang addPreferencesFromResourceIfEnabled(glimpPlugin, rootKey) addPreferencesFromResourceIfEnabled(careportalPlugin, rootKey) addPreferencesFromResourceIfEnabled(loopPlugin, rootKey, Config.APS) - addPreferencesFromResourceIfEnabled(openAPSMAPlugin, rootKey, Config.APS) addPreferencesFromResourceIfEnabled(openAPSAMAPlugin, rootKey, Config.APS) addPreferencesFromResourceIfEnabled(openAPSSMBPlugin, rootKey, Config.APS) addPreferencesFromResourceIfEnabled(sensitivityAAPSPlugin, rootKey) diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java index 0d65d80f6b..661eaea15f 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java @@ -234,7 +234,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { new java.util.TimerTask() { @Override public void run() { - RxBus.Companion.getINSTANCE().send(new EventRefreshOverview("resetDatabases")); + RxBus.Companion.getINSTANCE().send(new EventRefreshOverview("resetDatabases", false)); } }, 3000 diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppComponent.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppComponent.kt index 68c95efe66..392056e8c8 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppComponent.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppComponent.kt @@ -12,8 +12,7 @@ import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.db.ProfileSwitch import info.nightscout.androidaps.plugins.aps.loop.APSResult import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalResultAMA -import info.nightscout.androidaps.plugins.aps.openAPSMA.DetermineBasalResultMA -import info.nightscout.androidaps.plugins.aps.openAPSMA.LoggerCallback +import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB import info.nightscout.androidaps.plugins.constraints.objectives.objectives.* @@ -55,7 +54,6 @@ interface AppComponent : AndroidInjector { fun injectPumpEnactResult(pumpEnactResult: PumpEnactResult) fun injectAPSResult(apsResult: APSResult) fun injectDetermineBasalResultSMB(determineBasalResultSMB: DetermineBasalResultSMB) - fun injectDetermineBasalResultMA(determineBasalResultMA: DetermineBasalResultMA) fun injectDetermineBasalResultAMA(determineBasalResultAMA: DetermineBasalResultAMA) fun injectDetermineBasalAdapterSMBJS(determineBasalAdapterSMBJS: DetermineBasalAdapterSMBJS) diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt index 933873bc5e..4eb2708a3f 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/AppModule.kt @@ -22,8 +22,7 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLoggerProduction import info.nightscout.androidaps.plugins.aps.loop.APSResult import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalResultAMA -import info.nightscout.androidaps.plugins.aps.openAPSMA.DetermineBasalResultMA -import info.nightscout.androidaps.plugins.aps.openAPSMA.LoggerCallback +import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB import info.nightscout.androidaps.plugins.configBuilder.PluginStore @@ -50,6 +49,7 @@ import info.nightscout.androidaps.queue.commands.* import info.nightscout.androidaps.setupwizard.SWEventListener import info.nightscout.androidaps.setupwizard.SWScreen import info.nightscout.androidaps.setupwizard.elements.* +import info.nightscout.androidaps.utils.CryptoUtil import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelperImplementation @@ -121,7 +121,6 @@ open class AppModule { @ContributesAndroidInjector fun apsResultInjector(): APSResult @ContributesAndroidInjector fun determineBasalResultSMBInjector(): DetermineBasalResultSMB - @ContributesAndroidInjector fun determineBasalResultMAInjector(): DetermineBasalResultMA @ContributesAndroidInjector fun determineBasalResultAMAInjector(): DetermineBasalResultAMA @ContributesAndroidInjector @@ -261,6 +260,7 @@ open class AppModule { @ContributesAndroidInjector fun graphDataInjector(): GraphData + @ContributesAndroidInjector fun cryptoUtilInjector(): CryptoUtil @ContributesAndroidInjector fun importExportPrefsInjector(): ImportExportPrefs @ContributesAndroidInjector fun encryptedPrefsFormatInjector(): EncryptedPrefsFormat @ContributesAndroidInjector fun classicPrefsFormatInjector(): ClassicPrefsFormat diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt index 581c8b84bd..05be5bbd9f 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/FragmentsModule.kt @@ -6,7 +6,6 @@ import info.nightscout.androidaps.activities.MyPreferenceFragment import info.nightscout.androidaps.dialogs.* import info.nightscout.androidaps.plugins.aps.loop.LoopFragment import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAFragment -import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAFragment import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBFragment import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderFragment import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesFragment @@ -64,7 +63,6 @@ abstract class FragmentsModule { @ContributesAndroidInjector abstract fun contributesLocalProfileFragment(): LocalProfileFragment @ContributesAndroidInjector abstract fun contributesObjectivesFragment(): ObjectivesFragment @ContributesAndroidInjector abstract fun contributesOpenAPSAMAFragment(): OpenAPSAMAFragment - @ContributesAndroidInjector abstract fun contributesOpenAPSMAFragment(): OpenAPSMAFragment @ContributesAndroidInjector abstract fun contributesOpenAPSSMBFragment(): OpenAPSSMBFragment @ContributesAndroidInjector abstract fun contributesOverviewFragment(): OverviewFragment @ContributesAndroidInjector abstract fun contributesLocalInsightFragment(): LocalInsightFragment diff --git a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/PluginsModule.kt b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/PluginsModule.kt index cc3694874f..16f454393e 100644 --- a/app/src/main/java/info/nightscout/androidaps/dependencyInjection/PluginsModule.kt +++ b/app/src/main/java/info/nightscout/androidaps/dependencyInjection/PluginsModule.kt @@ -11,7 +11,6 @@ import info.nightscout.androidaps.Config import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin -import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin import info.nightscout.androidaps.plugins.constraints.dstHelper.DstHelperPlugin @@ -188,36 +187,30 @@ abstract class PluginsModule { @APS @IntoMap @IntKey(210) - abstract fun bindOpenAPSMAPlugin(plugin: OpenAPSMAPlugin): PluginBase - - @Binds - @APS - @IntoMap - @IntKey(220) abstract fun bindOpenAPSAMAPlugin(plugin: OpenAPSAMAPlugin): PluginBase @Binds @APS @IntoMap - @IntKey(230) + @IntKey(220) abstract fun bindOpenAPSSMBPlugin(plugin: OpenAPSSMBPlugin): PluginBase @Binds @AllConfigs @IntoMap - @IntKey(240) + @IntKey(230) abstract fun bindNSProfilePlugin(plugin: NSProfilePlugin): PluginBase @Binds @NotNSClient @IntoMap - @IntKey(250) + @IntKey(240) abstract fun bindLocalProfilePlugin(plugin: LocalProfilePlugin): PluginBase @Binds @AllConfigs @IntoMap - @IntKey(255) + @IntKey(250) abstract fun bindAutomationPlugin(plugin: AutomationPlugin): PluginBase @Binds diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventRefreshOverview.kt b/app/src/main/java/info/nightscout/androidaps/events/EventRefreshOverview.kt index 533a25dd40..25b22d4e81 100644 --- a/app/src/main/java/info/nightscout/androidaps/events/EventRefreshOverview.kt +++ b/app/src/main/java/info/nightscout/androidaps/events/EventRefreshOverview.kt @@ -1,3 +1,3 @@ package info.nightscout.androidaps.events -class EventRefreshOverview(var from: String) : Event() +class EventRefreshOverview(var from: String, val now : Boolean = false) : Event() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateGui.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/events/EventOpenAPSUpdateGui.kt similarity index 62% rename from app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateGui.kt rename to app/src/main/java/info/nightscout/androidaps/plugins/aps/events/EventOpenAPSUpdateGui.kt index 2b642c6880..004bdacf41 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateGui.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/events/EventOpenAPSUpdateGui.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.aps.openAPSMA.events +package info.nightscout.androidaps.plugins.aps.events import info.nightscout.androidaps.events.EventUpdateGui diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateResultGui.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/events/EventOpenAPSUpdateResultGui.kt similarity index 66% rename from app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateResultGui.kt rename to app/src/main/java/info/nightscout/androidaps/plugins/aps/events/EventOpenAPSUpdateResultGui.kt index 4ba02b8755..893309c9ba 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/events/EventOpenAPSUpdateResultGui.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/events/EventOpenAPSUpdateResultGui.kt @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.aps.openAPSMA.events +package info.nightscout.androidaps.plugins.aps.events import info.nightscout.androidaps.events.EventUpdateGui diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/LoggerCallback.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/logger/LoggerCallback.java similarity index 96% rename from app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/LoggerCallback.java rename to app/src/main/java/info/nightscout/androidaps/plugins/aps/logger/LoggerCallback.java index d7e0c44d42..815cf2fa24 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/LoggerCallback.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/logger/LoggerCallback.java @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.aps.openAPSMA; +package info.nightscout.androidaps.plugins.aps.logger; import org.mozilla.javascript.ScriptableObject; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.java index 5606014c0f..50a6c6e018 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/DetermineBasalAdapterAMAJS.java @@ -29,7 +29,7 @@ import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.aps.loop.ScriptReader; -import info.nightscout.androidaps.plugins.aps.openAPSMA.LoggerCallback; +import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback; import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt index 6bf087417b..342a1395f5 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAFragment.kt @@ -9,8 +9,8 @@ import dagger.android.support.DaggerFragment import info.nightscout.androidaps.R import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui -import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui +import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui +import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.java index bc80b755fa..cea65a14d9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSAMA/OpenAPSAMAPlugin.java @@ -23,8 +23,8 @@ import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.aps.loop.APSResult; import info.nightscout.androidaps.plugins.aps.loop.ScriptReader; -import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui; -import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui; +import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui; +import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/DetermineBasalAdapterMAJS.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/DetermineBasalAdapterMAJS.java deleted file mode 100644 index c7733d4eb7..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/DetermineBasalAdapterMAJS.java +++ /dev/null @@ -1,232 +0,0 @@ -package info.nightscout.androidaps.plugins.aps.openAPSMA; - -import org.json.JSONException; -import org.json.JSONObject; -import org.mozilla.javascript.Context; -import org.mozilla.javascript.Function; -import org.mozilla.javascript.NativeJSON; -import org.mozilla.javascript.NativeObject; -import org.mozilla.javascript.RhinoException; -import org.mozilla.javascript.Scriptable; -import org.mozilla.javascript.ScriptableObject; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.nio.charset.StandardCharsets; - -import javax.annotation.Nullable; -import javax.inject.Inject; - -import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.Constants; -import info.nightscout.androidaps.R; -import info.nightscout.androidaps.data.IobTotal; -import info.nightscout.androidaps.data.MealData; -import info.nightscout.androidaps.data.Profile; -import info.nightscout.androidaps.db.TemporaryBasal; -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.L; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.aps.loop.ScriptReader; -import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; -import info.nightscout.androidaps.utils.SP; - -public class DetermineBasalAdapterMAJS { - - private HasAndroidInjector injector; - @Inject AAPSLogger aapsLogger; - @Inject ProfileFunction profileFunction; - @Inject TreatmentsPlugin treatmentsPlugin; - - private ScriptReader mScriptReader; - private JSONObject mProfile; - private JSONObject mGlucoseStatus; - private JSONObject mIobData; - private JSONObject mMealData; - private JSONObject mCurrentTemp; - - private String storedCurrentTemp = null; - private String storedIobData = null; - private String storedGlucoseStatus = null; - private String storedProfile = null; - private String storedMeal_data = null; - - DetermineBasalAdapterMAJS(ScriptReader scriptReader, HasAndroidInjector injector) { - injector.androidInjector().inject(this); - mScriptReader = scriptReader; - this.injector = injector; - } - - @Nullable - public DetermineBasalResultMA invoke() { - DetermineBasalResultMA determineBasalResultMA = null; - - Context rhino = Context.enter(); - Scriptable scope = rhino.initStandardObjects(); - // Turn off optimization to make Rhino Android compatible - rhino.setOptimizationLevel(-1); - - try { - - //register logger callback for console.log and console.error - ScriptableObject.defineClass(scope, LoggerCallback.class); - Scriptable myLogger = rhino.newObject(scope, "LoggerCallback", null); - scope.put("console", scope, myLogger); - - //set module parent - rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null); - - //generate functions "determine_basal" and "setTempBasal" - rhino.evaluateString(scope, readFile("OpenAPSMA/determine-basal.js"), "JavaScript", 0, null); - - String setTempBasalCode = "var setTempBasal = function (rate, duration, profile, rT, offline) {" + - "rT.duration = duration;\n" + - " rT.rate = rate;" + - "return rT;" + - "};"; - rhino.evaluateString(scope, setTempBasalCode, "setTempBasal.js", 0, null); - Object determineBasalObj = scope.get("determine_basal", scope); - Object setTempBasalObj = scope.get("setTempBasal", scope); - - //call determine-basal - if (determineBasalObj instanceof Function && setTempBasalObj instanceof Function) { - Function determineBasalJS = (Function) determineBasalObj; - Function setTempBasalJS = (Function) setTempBasalObj; - - //prepare parameters - Object[] params = new Object[]{ - makeParam(mGlucoseStatus, rhino, scope), - makeParam(mCurrentTemp, rhino, scope), - makeParam(mIobData, rhino, scope), - makeParam(mProfile, rhino, scope), - "undefined", - makeParam(mMealData, rhino, scope), - setTempBasalJS}; - - NativeObject jsResult = (NativeObject) determineBasalJS.call(rhino, scope, scope, params); - - // Parse the jsResult object to a JSON-String - String result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString(); - aapsLogger.debug(LTag.APS, "Result: " + result); - try { - determineBasalResultMA = new DetermineBasalResultMA(injector, jsResult, new JSONObject(result)); - } catch (JSONException e) { - aapsLogger.error(LTag.APS, "Unhandled exception", e); - } - } else { - aapsLogger.debug(LTag.APS, "Problem loading JS Functions"); - } - } catch (IOException e) { - aapsLogger.error(LTag.APS, "IOException"); - } catch (RhinoException e) { - aapsLogger.error(LTag.APS, "RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString()); - } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) { - aapsLogger.error(LTag.APS, e.toString()); - } finally { - Context.exit(); - } - - storedGlucoseStatus = mGlucoseStatus.toString(); - storedIobData = mIobData.toString(); - storedCurrentTemp = mCurrentTemp.toString(); - storedProfile = mProfile.toString(); - storedMeal_data = mMealData.toString(); - - return determineBasalResultMA; - } - - String getGlucoseStatusParam() { - return storedGlucoseStatus; - } - - String getCurrentTempParam() { - return storedCurrentTemp; - } - - String getIobDataParam() { - return storedIobData; - } - - String getProfileParam() { - return storedProfile; - } - - String getMealDataParam() { - return storedMeal_data; - } - - public void setData(Profile profile, - double maxIob, - double maxBasal, - double minBg, - double maxBg, - double targetBg, - double basalRate, - IobTotal iobData, - GlucoseStatus glucoseStatus, - MealData mealData) throws JSONException { - - mProfile = new JSONObject(); - mProfile.put("max_iob", maxIob); - mProfile.put("dia", Math.min(profile.getDia(), 3d)); - mProfile.put("type", "current"); - mProfile.put("max_daily_basal", profile.getMaxDailyBasal()); - mProfile.put("max_basal", maxBasal); - mProfile.put("min_bg", minBg); - mProfile.put("max_bg", maxBg); - mProfile.put("target_bg", targetBg); - mProfile.put("carb_ratio", profile.getIc()); - mProfile.put("sens", profile.getIsfMgdl()); - - mProfile.put("current_basal", basalRate); - - if (profileFunction.getUnits().equals(Constants.MMOL)) { - mProfile.put("out_units", "mmol/L"); - } - - long now = System.currentTimeMillis(); - TemporaryBasal tb = treatmentsPlugin.getTempBasalFromHistory(now); - - mCurrentTemp = new JSONObject(); - mCurrentTemp.put("duration", tb != null ? tb.getPlannedRemainingMinutes() : 0); - mCurrentTemp.put("rate", tb != null ? tb.tempBasalConvertedToAbsolute(now, profile) : 0d); - - mIobData = new JSONObject(); - mIobData.put("iob", iobData.iob); //netIob - mIobData.put("activity", iobData.activity); //netActivity - mIobData.put("bolussnooze", iobData.bolussnooze); //bolusIob - mIobData.put("basaliob", iobData.basaliob); - mIobData.put("netbasalinsulin", iobData.netbasalinsulin); - mIobData.put("hightempinsulin", iobData.hightempinsulin); - - mGlucoseStatus = new JSONObject(); - mGlucoseStatus.put("glucose", glucoseStatus.glucose); - if (SP.getBoolean(R.string.key_always_use_shortavg, false)) { - mGlucoseStatus.put("delta", glucoseStatus.short_avgdelta); - } else { - mGlucoseStatus.put("delta", glucoseStatus.delta); - } - mGlucoseStatus.put("avgdelta", glucoseStatus.avgdelta); - - mMealData = new JSONObject(); - mMealData.put("carbs", mealData.carbs); - mMealData.put("boluses", mealData.boluses); - } - - private String readFile(String filename) throws IOException { - byte[] bytes = mScriptReader.readFile(filename); - String string = new String(bytes, StandardCharsets.UTF_8); - if (string.startsWith("#!/usr/bin/env node")) { - string = string.substring(20); - } - return string; - } - - private Object makeParam(JSONObject jsonObject, Context rhino, Scriptable scope) { - Object param = NativeJSON.parse(rhino, scope, jsonObject.toString(), (context, scriptable, scriptable1, objects) -> objects[1]); - return param; - } - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/DetermineBasalResultMA.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/DetermineBasalResultMA.java deleted file mode 100644 index 298b313540..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/DetermineBasalResultMA.java +++ /dev/null @@ -1,79 +0,0 @@ -package info.nightscout.androidaps.plugins.aps.openAPSMA; - -import org.json.JSONException; -import org.json.JSONObject; -import org.mozilla.javascript.NativeObject; - -import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.aps.loop.APSResult; - -public class DetermineBasalResultMA extends APSResult { - private AAPSLogger aapsLogger; - - private double eventualBG; - private double snoozeBG; - private String mealAssist; - - DetermineBasalResultMA(HasAndroidInjector injector, NativeObject result, JSONObject j) { - this(injector); - json = j; - if (result.containsKey("error")) { - reason = (String) result.get("error"); - tempBasalRequested = false; - rate = -1; - duration = -1; - mealAssist = ""; - } else { - reason = result.get("reason").toString(); - eventualBG = (Double) result.get("eventualBG"); - snoozeBG = (Double) result.get("snoozeBG"); - if (result.containsKey("rate")) { - rate = (Double) result.get("rate"); - if (rate < 0d) rate = 0d; - tempBasalRequested = true; - } else { - rate = -1; - tempBasalRequested = false; - } - if (result.containsKey("duration")) { - duration = ((Double) result.get("duration")).intValue(); - //changeRequested as above - } else { - duration = -1; - tempBasalRequested = false; - } - if (result.containsKey("mealAssist")) { - mealAssist = result.get("mealAssist").toString(); - } else mealAssist = ""; - } - } - - private DetermineBasalResultMA(HasAndroidInjector injector) { - super(injector); - } - - @Override - public DetermineBasalResultMA newAndClone(HasAndroidInjector injector) { - DetermineBasalResultMA newResult = new DetermineBasalResultMA(injector); - doClone(newResult); - - newResult.eventualBG = eventualBG; - newResult.snoozeBG = snoozeBG; - newResult.mealAssist = mealAssist; - return newResult; - } - - @Override - public JSONObject json() { - try { - JSONObject ret = new JSONObject(this.json.toString()); - return ret; - } catch (JSONException e) { - aapsLogger.error(LTag.APS, "Unhandled exception", e); - } - return null; - } - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAFragment.kt deleted file mode 100644 index 5a92764b46..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAFragment.kt +++ /dev/null @@ -1,98 +0,0 @@ -package info.nightscout.androidaps.plugins.aps.openAPSMA - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import dagger.android.support.DaggerFragment -import info.nightscout.androidaps.R -import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui -import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui -import info.nightscout.androidaps.plugins.bus.RxBusWrapper -import info.nightscout.androidaps.utils.DateUtil -import info.nightscout.androidaps.utils.FabricPrivacy -import info.nightscout.androidaps.utils.JSONFormatter -import info.nightscout.androidaps.utils.extensions.plusAssign -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.CompositeDisposable -import kotlinx.android.synthetic.main.openapsama_fragment.* -import javax.inject.Inject - -class OpenAPSMAFragment : DaggerFragment() { - private var disposable: CompositeDisposable = CompositeDisposable() - - @Inject lateinit var rxBus: RxBusWrapper - @Inject lateinit var fabricPrivacy: FabricPrivacy - @Inject lateinit var openAPSMAPlugin: OpenAPSMAPlugin - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.openapsma_fragment, container, false) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - openapsma_run.setOnClickListener { - openAPSMAPlugin.invoke("OpenAPSMA button", false) - } - - } - - @Synchronized - override fun onResume() { - super.onResume() - - disposable += rxBus - .toObservable(EventOpenAPSUpdateGui::class.java) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ - updateGUI() - }, { fabricPrivacy.logException(it) }) - disposable += rxBus - .toObservable(EventOpenAPSUpdateResultGui::class.java) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ - updateResultGUI(it.text) - }, { fabricPrivacy.logException(it) }) - updateGUI() - } - - @Synchronized - override fun onPause() { - super.onPause() - disposable.clear() - } - - @Synchronized - private fun updateGUI() { - if (openapsma_result == null) return - openAPSMAPlugin.lastAPSResult?.let { lastAPSResult -> - openapsma_result.text = JSONFormatter.format(lastAPSResult.json) - openapsma_request.text = lastAPSResult.toSpanned() - } - openAPSMAPlugin.lastDetermineBasalAdapterMAJS?.let { determineBasalAdapterMAJS -> - openapsma_glucosestatus.text = JSONFormatter.format(determineBasalAdapterMAJS.glucoseStatusParam) - openapsma_currenttemp.text = JSONFormatter.format(determineBasalAdapterMAJS.currentTempParam) - openapsma_iobdata.text = JSONFormatter.format(determineBasalAdapterMAJS.iobDataParam) - openapsma_profile.text = JSONFormatter.format(determineBasalAdapterMAJS.profileParam) - openapsma_mealdata.text = JSONFormatter.format(determineBasalAdapterMAJS.mealDataParam) - } - if (openAPSMAPlugin.lastAPSRun != 0L) { - openapsma_lastrun.text = DateUtil.dateAndTimeString(openAPSMAPlugin.lastAPSRun) - } - } - - @Synchronized - private fun updateResultGUI(text: String) { - if (openapsma_result == null) return - openapsma_result.text = text - openapsma_glucosestatus.text = "" - openapsma_currenttemp.text = "" - openapsma_iobdata.text = "" - openapsma_profile.text = "" - openapsma_mealdata.text = "" - openapsma_request.text = "" - openapsma_lastrun.text = "" - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAPlugin.java deleted file mode 100644 index a1b8c24d02..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSMA/OpenAPSMAPlugin.java +++ /dev/null @@ -1,232 +0,0 @@ -package info.nightscout.androidaps.plugins.aps.openAPSMA; - -import android.content.Context; - -import org.json.JSONException; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import dagger.android.HasAndroidInjector; -import info.nightscout.androidaps.R; -import info.nightscout.androidaps.data.IobTotal; -import info.nightscout.androidaps.data.MealData; -import info.nightscout.androidaps.data.Profile; -import info.nightscout.androidaps.db.TempTarget; -import info.nightscout.androidaps.interfaces.APSInterface; -import info.nightscout.androidaps.interfaces.ActivePluginProvider; -import info.nightscout.androidaps.interfaces.PluginBase; -import info.nightscout.androidaps.interfaces.PluginDescription; -import info.nightscout.androidaps.interfaces.PluginType; -import info.nightscout.androidaps.interfaces.PumpInterface; -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.aps.loop.APSResult; -import info.nightscout.androidaps.plugins.aps.loop.ScriptReader; -import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui; -import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui; -import info.nightscout.androidaps.plugins.bus.RxBusWrapper; -import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; -import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; -import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin; -import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin; -import info.nightscout.androidaps.utils.DateUtil; -import info.nightscout.androidaps.utils.FabricPrivacy; -import info.nightscout.androidaps.utils.HardLimits; -import info.nightscout.androidaps.utils.Profiler; -import info.nightscout.androidaps.utils.Round; -import info.nightscout.androidaps.utils.resources.ResourceHelper; - -@Singleton -public class OpenAPSMAPlugin extends PluginBase implements APSInterface { - private final RxBusWrapper rxBus; - private final ConstraintChecker constraintChecker; - private final ResourceHelper resourceHelper; - private final ProfileFunction profileFunction; - private final Context context; - private final ActivePluginProvider activePlugin; - private final TreatmentsPlugin treatmentsPlugin; - private final IobCobCalculatorPlugin iobCobCalculatorPlugin; - private final HardLimits hardLimits; - - // last values - DetermineBasalAdapterMAJS lastDetermineBasalAdapterMAJS = null; - long lastAPSRun = 0; - DetermineBasalResultMA lastAPSResult = null; - - @Inject - public OpenAPSMAPlugin( - HasAndroidInjector injector, - AAPSLogger aapsLogger, - RxBusWrapper rxBus, - ConstraintChecker constraintChecker, - ResourceHelper resourceHelper, - ProfileFunction profileFunction, - Context context, - ActivePluginProvider activePlugin, - TreatmentsPlugin treatmentsPlugin, - IobCobCalculatorPlugin iobCobCalculatorPlugin, - HardLimits hardLimits - ) { - super(new PluginDescription() - .mainType(PluginType.APS) - .fragmentClass(OpenAPSMAFragment.class.getName()) - .pluginName(R.string.openapsma) - .shortName(R.string.oaps_shortname) - .preferencesId(R.xml.pref_openapsma) - .description(R.string.description_ma), - aapsLogger, resourceHelper, injector - ); - - this.constraintChecker = constraintChecker; - this.resourceHelper = resourceHelper; - this.profileFunction = profileFunction; - this.context = context; - this.rxBus = rxBus; - this.activePlugin = activePlugin; - this.treatmentsPlugin = treatmentsPlugin; - this.iobCobCalculatorPlugin = iobCobCalculatorPlugin; - this.hardLimits = hardLimits; - } - - @Override - public boolean specialEnableCondition() { - try { - PumpInterface pump = activePlugin.getActivePump(); - return pump.getPumpDescription().isTempBasalCapable; - } catch (Exception ignored) { - // may fail during initialization - return true; - } - } - - @Override - public boolean specialShowInListCondition() { - PumpInterface pump = activePlugin.getActivePump(); - return pump.getPumpDescription().isTempBasalCapable; - } - - @Override - public APSResult getLastAPSResult() { - return lastAPSResult; - } - - @Override - public long getLastAPSRun() { - return lastAPSRun; - } - - @Override - public void invoke(String initiator, boolean tempBasalFallback) { - getAapsLogger().debug(LTag.APS, "invoke from " + initiator + " tempBasalFallback: " + tempBasalFallback); - lastAPSResult = null; - DetermineBasalAdapterMAJS determineBasalAdapterMAJS; - determineBasalAdapterMAJS = new DetermineBasalAdapterMAJS(new ScriptReader(context), getInjector()); - - GlucoseStatus glucoseStatus = new GlucoseStatus(getInjector()).getGlucoseStatusData(); - Profile profile = profileFunction.getProfile(); - PumpInterface pump = activePlugin.getActivePump(); - - if (profile == null) { - rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.noprofileselected))); - getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected)); - return; - } - - if (!isEnabled(PluginType.APS)) { - rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_disabled))); - getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.openapsma_disabled)); - return; - } - - if (glucoseStatus == null) { - rxBus.send(new EventOpenAPSUpdateResultGui(resourceHelper.gs(R.string.openapsma_noglucosedata))); - getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.openapsma_noglucosedata)); - return; - } - - double maxBasal = constraintChecker.getMaxBasalAllowed(profile).value(); - - double minBg = profile.getTargetLowMgdl(); - double maxBg = profile.getTargetHighMgdl(); - double targetBg = profile.getTargetMgdl(); - - minBg = Round.roundTo(minBg, 0.1d); - maxBg = Round.roundTo(maxBg, 0.1d); - - long start = System.currentTimeMillis(); - treatmentsPlugin.updateTotalIOBTreatments(); - treatmentsPlugin.updateTotalIOBTempBasals(); - IobTotal bolusIob = treatmentsPlugin.getLastCalculationTreatments(); - IobTotal basalIob = treatmentsPlugin.getLastCalculationTempBasals(); - - IobTotal iobTotal = IobTotal.combine(bolusIob, basalIob).round(); - - MealData mealData = iobCobCalculatorPlugin.getMealData(); - - double maxIob = constraintChecker.getMaxIOBAllowed().value(); - Profiler.log(getAapsLogger(), LTag.APS, "MA data gathering", start); - - minBg = hardLimits.verifyHardLimits(minBg, "minBg", hardLimits.getVERY_HARD_LIMIT_MIN_BG()[0], hardLimits.getVERY_HARD_LIMIT_MIN_BG()[1]); - maxBg = hardLimits.verifyHardLimits(maxBg, "maxBg", hardLimits.getVERY_HARD_LIMIT_MAX_BG()[0], hardLimits.getVERY_HARD_LIMIT_MAX_BG()[1]); - targetBg = hardLimits.verifyHardLimits(targetBg, "targetBg", hardLimits.getVERY_HARD_LIMIT_TARGET_BG()[0], hardLimits.getVERY_HARD_LIMIT_TARGET_BG()[1]); - - TempTarget tempTarget = treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis()); - if (tempTarget != null) { - minBg = hardLimits.verifyHardLimits(tempTarget.low, "minBg", hardLimits.getVERY_HARD_LIMIT_TEMP_MIN_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_MIN_BG()[1]); - maxBg = hardLimits.verifyHardLimits(tempTarget.high, "maxBg", hardLimits.getVERY_HARD_LIMIT_TEMP_MAX_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_MAX_BG()[1]); - targetBg = hardLimits.verifyHardLimits(tempTarget.target(), "targetBg", hardLimits.getVERY_HARD_LIMIT_TEMP_TARGET_BG()[0], hardLimits.getVERY_HARD_LIMIT_TEMP_TARGET_BG()[1]); - } - - if (!hardLimits.checkOnlyHardLimits(profile.getDia(), "dia", hardLimits.getMINDIA(), hardLimits.getMAXDIA())) - return; - if (!hardLimits.checkOnlyHardLimits(profile.getIcTimeFromMidnight(Profile.secondsFromMidnight()), "carbratio", hardLimits.getMINIC(), hardLimits.getMAXIC())) - return; - if (!hardLimits.checkOnlyHardLimits(profile.getIsfMgdl(), "sens", hardLimits.getMINISF(), hardLimits.getMAXISF())) - return; - if (!hardLimits.checkOnlyHardLimits(profile.getMaxDailyBasal(), "max_daily_basal", 0.02, hardLimits.maxBasal())) - return; - if (!hardLimits.checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, hardLimits.maxBasal())) - return; - - start = System.currentTimeMillis(); - try { - determineBasalAdapterMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, activePlugin.getActivePump().getBaseBasalRate(), iobTotal, glucoseStatus, mealData); - } catch (JSONException e) { - FabricPrivacy.getInstance().logException(e); - return; - } - Profiler.log(getAapsLogger(), LTag.APS, "MA calculation", start); - - - long now = System.currentTimeMillis(); - - DetermineBasalResultMA determineBasalResultMA = determineBasalAdapterMAJS.invoke(); - if (determineBasalResultMA == null) { - getAapsLogger().error(LTag.APS, "MA calculation returned null"); - lastDetermineBasalAdapterMAJS = null; - lastAPSResult = null; - lastAPSRun = 0; - } else { - // Fix bug determine basal - if (determineBasalResultMA.rate == 0d && determineBasalResultMA.duration == 0 && !treatmentsPlugin.isTempBasalInProgress()) - determineBasalResultMA.tempBasalRequested = false; - - determineBasalResultMA.iob = iobTotal; - - try { - determineBasalResultMA.json.put("timestamp", DateUtil.toISOString(now)); - } catch (JSONException e) { - getAapsLogger().error(LTag.APS, "Unhandled exception", e); - } - - lastDetermineBasalAdapterMAJS = determineBasalAdapterMAJS; - lastAPSResult = determineBasalResultMA; - lastAPSRun = now; - } - rxBus.send(new EventOpenAPSUpdateGui()); - } - - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.java index af56162640..4d3a0db704 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/DetermineBasalAdapterSMBJS.java @@ -29,7 +29,7 @@ import info.nightscout.androidaps.db.TemporaryBasal; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.aps.loop.ScriptReader; -import info.nightscout.androidaps.plugins.aps.openAPSMA.LoggerCallback; +import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt index ec60365f2e..95b0f7f7b8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBFragment.kt @@ -10,8 +10,8 @@ import dagger.android.support.DaggerFragment import info.nightscout.androidaps.R import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag -import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui -import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui +import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui +import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.FabricPrivacy diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java index 6081849d59..51650891ee 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/aps/openAPSSMB/OpenAPSSMBPlugin.java @@ -26,8 +26,8 @@ import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.aps.loop.APSResult; import info.nightscout.androidaps.plugins.aps.loop.ScriptReader; -import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui; -import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui; +import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui; +import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java index a344d8b56a..a32b7233e1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPlugin.java @@ -20,7 +20,6 @@ import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin; -import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin; import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; @@ -42,7 +41,6 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface { private RxBusWrapper rxBus; private ConstraintChecker constraintChecker; private OpenAPSAMAPlugin openAPSAMAPlugin; - private OpenAPSMAPlugin openAPSMAPlugin; private OpenAPSSMBPlugin openAPSSMBPlugin; private SensitivityOref1Plugin sensitivityOref1Plugin; private ActivePluginProvider activePlugin; @@ -59,7 +57,6 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface { RxBusWrapper rxBus, ConstraintChecker constraintChecker, OpenAPSAMAPlugin openAPSAMAPlugin, - OpenAPSMAPlugin openAPSMAPlugin, OpenAPSSMBPlugin openAPSSMBPlugin, SensitivityOref1Plugin sensitivityOref1Plugin, ActivePluginProvider activePlugin, @@ -80,7 +77,6 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface { this.rxBus = rxBus; this.constraintChecker = constraintChecker; this.openAPSAMAPlugin = openAPSAMAPlugin; - this.openAPSMAPlugin = openAPSMAPlugin; this.openAPSSMBPlugin = openAPSSMBPlugin; this.sensitivityOref1Plugin = sensitivityOref1Plugin; this.activePlugin = activePlugin; @@ -276,8 +272,6 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface { maxIobPref = sp.getDouble(R.string.key_openapsma_max_iob, 1.5d); maxIob.setIfSmaller(getAapsLogger(), maxIobPref, String.format(getResourceHelper().gs(R.string.limitingiob), maxIobPref, getResourceHelper().gs(R.string.maxvalueinpreferences)), this); - if (openAPSMAPlugin.isEnabled(PluginType.APS)) - maxIob.setIfSmaller(getAapsLogger(), hardLimits.maxIobAMA(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.maxIobAMA(), getResourceHelper().gs(R.string.hardlimit)), this); if (openAPSAMAPlugin.isEnabled(PluginType.APS)) maxIob.setIfSmaller(getAapsLogger(), hardLimits.maxIobAMA(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.maxIobAMA(), getResourceHelper().gs(R.string.hardlimit)), this); if (openAPSSMBPlugin.isEnabled(PluginType.APS)) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt index 3b640a5496..6380bd5fcf 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/dataBroadcaster/DataBroadcastPlugin.kt @@ -22,7 +22,7 @@ import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin -import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui +import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/EncryptedPrefsFormat.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/EncryptedPrefsFormat.kt index ec70c679da..1d5152b038 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/EncryptedPrefsFormat.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/maintenance/formats/EncryptedPrefsFormat.kt @@ -18,6 +18,7 @@ import javax.inject.Singleton @Singleton class EncryptedPrefsFormat @Inject constructor( private var resourceHelper: ResourceHelper, + private var cryptoUtil: CryptoUtil, private var storage: Storage ) : PrefsFormat { @@ -58,14 +59,14 @@ class EncryptedPrefsFormat @Inject constructor( var encodedContent = "" if (encrypted) { - val salt = CryptoUtil.mineSalt() + val salt = cryptoUtil.mineSalt() val rawContent = content.toString() - val contentAttempt = CryptoUtil.encrypt(masterPassword!!, salt, rawContent) + val contentAttempt = cryptoUtil.encrypt(masterPassword!!, salt, rawContent) if (contentAttempt != null) { encodedContent = contentAttempt security.put("algorithm", "v1") security.put("salt", salt.toHex()) - security.put("content_hash", CryptoUtil.sha256(rawContent)) + security.put("content_hash", cryptoUtil.sha256(rawContent)) } else { // fallback when encryption does not work encrypted = false @@ -80,7 +81,7 @@ class EncryptedPrefsFormat @Inject constructor( container.put("content", if (encrypted) encodedContent else content) var fileContents = container.toString(2) - val fileHash = CryptoUtil.hmac256(fileContents, KEY_CONSCIENCE) + val fileHash = cryptoUtil.hmac256(fileContents, KEY_CONSCIENCE) fileContents = fileContents.replace(Regex("(\\\"file_hash\\\"\\s*\\:\\s*\\\")(--to-be-calculated--)(\\\")"), "$1" + fileHash + "$3") @@ -102,7 +103,7 @@ class EncryptedPrefsFormat @Inject constructor( val jsonBody = storage.getFileContents(file) val fileContents = jsonBody.replace(Regex("(?is)(\\\"file_hash\\\"\\s*\\:\\s*\\\")([^\"]*)(\\\")"), "$1--to-be-calculated--$3") - val calculatedFileHash = CryptoUtil.hmac256(fileContents, KEY_CONSCIENCE) + val calculatedFileHash = cryptoUtil.hmac256(fileContents, KEY_CONSCIENCE) val container = JSONObject(jsonBody) if (container.has(PrefsMetadataKey.FILE_FORMAT.key) && container.has("security") && container.has("content") && container.has("metadata")) { @@ -144,11 +145,11 @@ class EncryptedPrefsFormat @Inject constructor( if (security.has("salt") && security.has("content_hash")) { val salt = security.getString("salt").hexStringToByteArray() - val decrypted = CryptoUtil.decrypt(masterPassword!!, salt, container.getString("content")) + val decrypted = cryptoUtil.decrypt(masterPassword!!, salt, container.getString("content")) if (decrypted != null) { try { - val contentHash = CryptoUtil.sha256(decrypted) + val contentHash = cryptoUtil.sha256(decrypted) if (contentHash == security.getString("content_hash")) { contentJsonObj = JSONObject(decrypted) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt index 8a0a6ee04b..28ab89ecba 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.kt @@ -5,6 +5,7 @@ import android.app.NotificationManager import android.content.ActivityNotFoundException import android.content.Context import android.content.Intent +import android.graphics.Color import android.graphics.Paint import android.os.Bundle import android.os.Handler @@ -17,7 +18,9 @@ import android.view.MenuItem import android.view.View import android.view.View.OnLongClickListener import android.view.ViewGroup +import android.widget.LinearLayout import androidx.recyclerview.widget.LinearLayoutManager +import com.jjoe64.graphview.GraphView import dagger.android.HasAndroidInjector import dagger.android.support.DaggerFragment import info.nightscout.androidaps.Config @@ -93,6 +96,7 @@ import java.util.concurrent.Executors import java.util.concurrent.ScheduledFuture import java.util.concurrent.TimeUnit import javax.inject.Inject +import kotlin.collections.ArrayList import kotlin.math.abs import kotlin.math.ceil import kotlin.math.max @@ -130,6 +134,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList private var smallWidth = false private var smallHeight = false private lateinit var dm: DisplayMetrics + private var axisWidth: Int = 0 private var rangeToDisplay = 6 // for graph private var loopHandler = Handler() private var refreshLoop: Runnable? = null @@ -137,6 +142,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList private val worker = Executors.newSingleThreadScheduledExecutor() private var scheduledUpdate: ScheduledFuture<*>? = null + private val secondaryGraphs = ArrayList() + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -173,15 +180,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList overview_notifications?.setHasFixedSize(false) overview_notifications?.layoutManager = LinearLayoutManager(view.context) - val axisWidth = if (dm.densityDpi <= 120) 3 else if (dm.densityDpi <= 160) 10 else if (dm.densityDpi <= 320) 35 else if (dm.densityDpi <= 420) 50 else if (dm.densityDpi <= 560) 70 else 80 + axisWidth = if (dm.densityDpi <= 120) 3 else if (dm.densityDpi <= 160) 10 else if (dm.densityDpi <= 320) 35 else if (dm.densityDpi <= 420) 50 else if (dm.densityDpi <= 560) 70 else 80 overview_bggraph?.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid) overview_bggraph?.gridLabelRenderer?.reloadStyles() - overview_iobgraph?.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid) - overview_iobgraph?.gridLabelRenderer?.reloadStyles() - overview_iobgraph?.gridLabelRenderer?.isHorizontalLabelsVisible = false overview_bggraph?.gridLabelRenderer?.labelVerticalWidth = axisWidth - overview_iobgraph?.gridLabelRenderer?.labelVerticalWidth = axisWidth - overview_iobgraph?.gridLabelRenderer?.numVerticalLabels = 3 + rangeToDisplay = sp.getInt(R.string.key_rangetodisplay, 6) overview_bggraph?.setOnLongClickListener { @@ -193,6 +196,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList false } overviewMenus.setupChartMenu(overview_chartMenuButton) + prepareGraphs() overview_accepttempbutton?.setOnClickListener(this) overview_treatmentbutton?.setOnClickListener(this) @@ -218,8 +222,12 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList super.onResume() disposable.add(rxBus .toObservable(EventRefreshOverview::class.java) - .observeOn(Schedulers.io()) - .subscribe({ scheduleUpdateGUI(it.from) }) { fabricPrivacy.logException(it) }) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + prepareGraphs() + if (it.now) updateGUI(it.from) + else scheduleUpdateGUI(it.from) + }) { fabricPrivacy.logException(it) }) disposable.add(rxBus .toObservable(EventExtendedBolusChange::class.java) .observeOn(Schedulers.io()) @@ -464,6 +472,30 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList } + private fun prepareGraphs() { + val numOfGraphs = overviewMenus.setting.size + + if (numOfGraphs != secondaryGraphs.size - 1) { + //aapsLogger.debug("New secondary graph count ${numOfGraphs-1}") + // rebuild needed + secondaryGraphs.clear() + overview_iobgraph.removeAllViews() + for (i in 1 until numOfGraphs) { + val graph = GraphView(context) + graph.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, resourceHelper.dpToPx(100)).also { it.setMargins(0, 0, 0, resourceHelper.dpToPx(10)) } + graph.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid) + graph.gridLabelRenderer?.reloadStyles() + graph.gridLabelRenderer?.isHorizontalLabelsVisible = false + graph.gridLabelRenderer?.labelVerticalWidth = axisWidth + graph.gridLabelRenderer?.numVerticalLabels = 3 + graph.viewport.backgroundColor = Color.argb(20, 255, 255, 255) // 8% of gray + overview_iobgraph.addView(graph) + secondaryGraphs.add(graph) + } + } + + } + private fun scheduleUpdateGUI(from: String) { class UpdateRunnable : Runnable { override fun run() { @@ -746,19 +778,20 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList graphData.addInRangeArea(fromTime, endTime, lowLine, highLine) // **** BG **** - if (predictionsAvailable && sp.getBoolean("showprediction", false)) graphData.addBgReadings(fromTime, toTime, lowLine, highLine, - apsResult?.predictions) else graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null) + if (predictionsAvailable && overviewMenus.setting[0][OverviewMenus.CharType.PRE.ordinal]) + graphData.addBgReadings(fromTime, toTime, lowLine, highLine, apsResult?.predictions) + else graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null) // set manual x bounds to have nice steps graphData.formatAxis(fromTime, endTime) // Treatments graphData.addTreatments(fromTime, endTime) - if (sp.getBoolean("showactivityprimary", true)) + if (overviewMenus.setting[0][OverviewMenus.CharType.ACT.ordinal]) graphData.addActivity(fromTime, endTime, false, 0.8) // add basal data - if (pump.pumpDescription.isTempBasalCapable && sp.getBoolean("showbasals", true)) + if (pump.pumpDescription.isTempBasalCapable && overviewMenus.setting[0][OverviewMenus.CharType.BAS.ordinal]) graphData.addBasals(fromTime, now, lowLine / graphData.maxY / 1.2) // add target line @@ -768,57 +801,53 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList graphData.addNowLine(now) // ------------------ 2nd graph - val secondGraphData = GraphData(injector, overview_iobgraph, iobCobCalculatorPlugin) - var useIobForScale = false - var useCobForScale = false - var useDevForScale = false - var useRatioForScale = false - var useDSForScale = false - var useIAForScale = false - // finally enforce drawing of graphs - when { - sp.getBoolean("showiob", true) -> - useIobForScale = true - sp.getBoolean("showcob", true) -> - useCobForScale = true - sp.getBoolean("showdeviations", false) -> - useDevForScale = true - sp.getBoolean("showratios", false) -> - useRatioForScale = true - sp.getBoolean("showactivitysecondary", false) -> - useIAForScale = true - sp.getBoolean("showdevslope", false) -> - useDSForScale = true + val secondaryGraphsData: ArrayList = ArrayList() + for (g in 0 until secondaryGraphs.size) { + val secondGraphData = GraphData(injector, secondaryGraphs[g], iobCobCalculatorPlugin) + var useIobForScale = false + var useCobForScale = false + var useDevForScale = false + var useRatioForScale = false + var useDSForScale = false + var useIAForScale = false + when { + overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true + overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true + overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true + overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true + overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal] -> useIAForScale = true + overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true + } + + if (overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, now, useIobForScale, 1.0, overviewMenus.setting[g + 1][OverviewMenus.CharType.PRE.ordinal]) + if (overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, now, useCobForScale, if (useCobForScale) 1.0 else 0.5) + if (overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0) + if (overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, now, useRatioForScale, 1.0) + if (overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal]) secondGraphData.addActivity(fromTime, endTime, useIAForScale, 0.8) + if (overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1.0) + + // set manual x bounds to have nice steps + secondGraphData.formatAxis(fromTime, endTime) + secondGraphData.addNowLine(now) + secondaryGraphsData.add(secondGraphData) } - if (sp.getBoolean("showiob", true)) secondGraphData.addIob(fromTime, now, useIobForScale, 1.0, sp.getBoolean("showprediction", false)) - if (sp.getBoolean("showcob", true)) secondGraphData.addCob(fromTime, now, useCobForScale, if (useCobForScale) 1.0 else 0.5) - if (sp.getBoolean("showdeviations", false)) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0) - if (sp.getBoolean("showratios", false)) secondGraphData.addRatio(fromTime, now, useRatioForScale, 1.0) - if (sp.getBoolean("showactivitysecondary", true)) secondGraphData.addActivity(fromTime, endTime, useIAForScale, 0.8) - if (sp.getBoolean("showdevslope", false) && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1.0) - - // **** NOW line **** - // set manual x bounds to have nice steps - secondGraphData.formatAxis(fromTime, endTime) - secondGraphData.addNowLine(now) - // do GUI update val activity = activity activity?.runOnUiThread { - if (sp.getBoolean("showiob", true) - || sp.getBoolean("showcob", true) - || sp.getBoolean("showdeviations", false) - || sp.getBoolean("showratios", false) - || sp.getBoolean("showactivitysecondary", false) - || sp.getBoolean("showdevslope", false)) { - overview_iobgraph?.visibility = View.VISIBLE - } else { - overview_iobgraph?.visibility = View.GONE - } // finally enforce drawing of graphs graphData.performUpdate() - secondGraphData.performUpdate() + for (g in 0 until secondaryGraphs.size) { + secondaryGraphs[g].visibility = ( + overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal] || + overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal] || + overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal] || + overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal] || + overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal] || + overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] + ).toVisibility() + secondaryGraphsData[g].performUpdate() + } } }).start() } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt index 3e3714a89d..0368974841 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewMenus.kt @@ -10,8 +10,12 @@ import android.view.Menu import android.view.MenuItem import android.view.View import android.widget.ImageButton +import androidx.annotation.ColorRes +import androidx.annotation.StringRes import androidx.appcompat.widget.PopupMenu import androidx.fragment.app.FragmentManager +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import info.nightscout.androidaps.Config import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.ErrorHelperActivity @@ -38,6 +42,7 @@ import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.buildHelper.BuildHelper import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP +import java.lang.reflect.Type import javax.inject.Inject import javax.inject.Singleton @@ -57,131 +62,95 @@ class OverviewMenus @Inject constructor( private val loopPlugin: LoopPlugin ) { - enum class CharType { - PRE, BAS, IOB, COB, DEV, SEN, ACTPRIM, ACTSEC, DEVSLOPE + enum class CharType(@StringRes val nameId: Int, @ColorRes val colorId: Int, val primary: Boolean, val secondary: Boolean) { + PRE(R.string.overview_show_predictions, R.color.prediction, primary = true, secondary = false), + BAS(R.string.overview_show_basals, R.color.basal, primary = true, secondary = false), + IOB(R.string.overview_show_iob, R.color.iob, primary = false, secondary = true), + COB(R.string.overview_show_cob, R.color.cob, primary = false, secondary = true), + DEV(R.string.overview_show_deviations, R.color.deviations, primary = false, secondary = true), + SEN(R.string.overview_show_sensitivity, R.color.ratio, primary = false, secondary = true), + ACT(R.string.overview_show_activity, R.color.activity, primary = true, secondary = true), + DEVSLOPE(R.string.overview_show_deviationslope, R.color.devslopepos, primary = false, secondary = true) + } + + companion object { + const val MAX_GRAPHS = 5 // including main + } + var setting: MutableList> = ArrayList() + + private fun storeGraphConfig() { + val sts = Gson().toJson(setting) + sp.putString(R.string.key_graphconfig, sts) + aapsLogger.debug(sts) + } + + private fun loadGraphConfig() { + val sts = sp.getString(R.string.key_graphconfig, "") + if (sts.isNotEmpty()) + setting = Gson().fromJson(sts, Array>::class.java).toMutableList() + else { + setting = ArrayList() + setting.add(Array(CharType.values().size) { true }) + } } fun setupChartMenu(chartButton: ImageButton) { + loadGraphConfig() + val numOfGraphs = setting.size // 1 main + x secondary + chartButton.setOnClickListener { v: View -> val predictionsAvailable: Boolean = when { Config.APS -> loopPlugin.lastRun?.request?.hasPredictions ?: false Config.NSCLIENT -> true else -> false } - //var item: MenuItem - val dividerItem: MenuItem - //var title: CharSequence - var titleMaxChars = 0 - //var s: SpannableString val popup = PopupMenu(v.context, v) - if (predictionsAvailable) { - val item = popup.menu.add(Menu.NONE, CharType.PRE.ordinal, Menu.NONE, "Predictions") - val title = item.title - if (titleMaxChars < title.length) titleMaxChars = title.length - val s = SpannableString(title) - s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.prediction)), 0, s.length, 0) - item.title = s - item.isCheckable = true - item.isChecked = sp.getBoolean("showprediction", true) + + for (g in 0 until numOfGraphs) { + if (g != 0 && g < numOfGraphs) { + val dividerItem = popup.menu.add(Menu.NONE, g, Menu.NONE, "------- " + "Graph" + " " + g + " -------") + dividerItem.isCheckable = true + dividerItem.isChecked = true + } + CharType.values().forEach { m -> + if (g == 0 && !m.primary) return@forEach + if (g > 0 && !m.secondary) return@forEach + var insert = true + if (m == CharType.PRE) insert = predictionsAvailable + if (m == CharType.DEVSLOPE) insert = buildHelper.isDev() + if (insert) { + val item = popup.menu.add(Menu.NONE, m.ordinal + 100 * (g + 1), Menu.NONE, resourceHelper.gs(m.nameId)) + val title = item.title + val s = SpannableString(title) + s.setSpan(ForegroundColorSpan(resourceHelper.gc(m.colorId)), 0, s.length, 0) + item.title = s + item.isCheckable = true + item.isChecked = setting[g][m.ordinal] + } + } } - run { - val item = popup.menu.add(Menu.NONE, CharType.BAS.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_basals)) - val title = item.title - if (titleMaxChars < title.length) titleMaxChars = title.length - val s = SpannableString(title) - s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.basal)), 0, s.length, 0) - item.title = s - item.isCheckable = true - item.isChecked = sp.getBoolean("showbasals", true) - } - run { - val item = popup.menu.add(Menu.NONE, CharType.ACTPRIM.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_activity)) - val title = item.title - if (titleMaxChars < title.length) titleMaxChars = title.length - val s = SpannableString(title) - s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.activity)), 0, s.length, 0) - item.title = s - item.isCheckable = true - item.isChecked = sp.getBoolean("showactivityprimary", true) - dividerItem = popup.menu.add("") - dividerItem.isEnabled = false - } - run { - val item = popup.menu.add(Menu.NONE, CharType.IOB.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_iob)) - val title = item.title - if (titleMaxChars < title.length) titleMaxChars = title.length - val s = SpannableString(title) - s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.iob)), 0, s.length, 0) - item.title = s - item.isCheckable = true - item.isChecked = sp.getBoolean("showiob", true) - } - run { - val item = popup.menu.add(Menu.NONE, CharType.COB.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_cob)) - val title = item.title - if (titleMaxChars < title.length) titleMaxChars = title.length - val s = SpannableString(title) - s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.cob)), 0, s.length, 0) - item.title = s - item.isCheckable = true - item.isChecked = sp.getBoolean("showcob", true) - } - run { - val item = popup.menu.add(Menu.NONE, CharType.DEV.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_deviations)) - val title = item.title - if (titleMaxChars < title.length) titleMaxChars = title.length - val s = SpannableString(title) - s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.deviations)), 0, s.length, 0) - item.title = s - item.isCheckable = true - item.isChecked = sp.getBoolean("showdeviations", false) - } - run { - val item = popup.menu.add(Menu.NONE, CharType.SEN.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_sensitivity)) - val title = item.title - if (titleMaxChars < title.length) titleMaxChars = title.length - val s = SpannableString(title) - s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.ratio)), 0, s.length, 0) - item.title = s - item.isCheckable = true - item.isChecked = sp.getBoolean("showratios", false) - } - run { - val item = popup.menu.add(Menu.NONE, CharType.ACTSEC.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_activity)) - val title = item.title - if (titleMaxChars < title.length) titleMaxChars = title.length - val s = SpannableString(title) - s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.activity)), 0, s.length, 0) - item.title = s - item.isCheckable = true - item.isChecked = sp.getBoolean("showactivitysecondary", true) - } - if (buildHelper.isDev()) { - val item = popup.menu.add(Menu.NONE, CharType.DEVSLOPE.ordinal, Menu.NONE, "Deviation slope") - val title = item.title - if (titleMaxChars < title.length) titleMaxChars = title.length - val s = SpannableString(title) - s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.devslopepos)), 0, s.length, 0) - item.title = s - item.isCheckable = true - item.isChecked = sp.getBoolean("showdevslope", false) + if (numOfGraphs < MAX_GRAPHS) { + val dividerItem = popup.menu.add(Menu.NONE, numOfGraphs, Menu.NONE, "------- " + "Graph" + " " + numOfGraphs + " -------") + dividerItem.isCheckable = true + dividerItem.isChecked = false } - // Fairly good estimate for required divider text size... - dividerItem.title = String(CharArray(titleMaxChars + 10)).replace("\u0000", "_") popup.setOnMenuItemClickListener { - when (it.itemId) { - CharType.PRE.ordinal -> sp.putBoolean("showprediction", !it.isChecked) - CharType.BAS.ordinal -> sp.putBoolean("showbasals", !it.isChecked) - CharType.IOB.ordinal -> sp.putBoolean("showiob", !it.isChecked) - CharType.COB.ordinal -> sp.putBoolean("showcob", !it.isChecked) - CharType.DEV.ordinal -> sp.putBoolean("showdeviations", !it.isChecked) - CharType.SEN.ordinal -> sp.putBoolean("showratios", !it.isChecked) - CharType.ACTPRIM.ordinal -> sp.putBoolean("showactivityprimary", !it.isChecked) - CharType.ACTSEC.ordinal -> sp.putBoolean("showactivitysecondary", !it.isChecked) - CharType.DEVSLOPE.ordinal -> sp.putBoolean("showdevslope", !it.isChecked) + // id < 100 graph header - divider 1, 2, 3 ..... + if (it.itemId == numOfGraphs) { + // add new empty + setting.add(Array(CharType.values().size) { false }) + } else if (it.itemId < 100) { + // remove graph + setting.removeAt(it.itemId) + } else { + val graphNumber = it.itemId / 100 - 1 + val item = it.itemId % 100 + setting[graphNumber][item] = !it.isChecked } - rxBus.send(EventRefreshOverview("OnMenuItemClickListener")) + storeGraphConfig() + setupChartMenu(chartButton) + rxBus.send(EventRefreshOverview("OnMenuItemClickListener", now = true)) return@setOnMenuItemClickListener true } chartButton.setImageResource(R.drawable.ic_arrow_drop_up_white_24dp) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.kt index 62c964238c..abff22eae3 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/wear/WearPlugin.kt @@ -11,7 +11,7 @@ import info.nightscout.androidaps.interfaces.PluginDescription import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin -import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui +import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinFragment.kt index 21737cac6d..c2e61f19b9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/insulin/InsulinFragment.kt @@ -25,6 +25,6 @@ class InsulinFragment : DaggerFragment() { insulin_name?.setText(activePlugin.getActiveInsulin().getFriendlyName()) insulin_comment?.setText(activePlugin.getActiveInsulin().getComment()) insulin_dia?.text = resourceHelper.gs(R.string.dia) + ": " + activePlugin.getActiveInsulin().getDia() + "h" - insuling_graph?.show(activePlugin.getActiveInsulin()) + insulin_graph?.show(activePlugin.getActiveInsulin()) } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java index 5700a235a3..5521396b6b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/combo/ComboPlugin.java @@ -644,7 +644,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr } finally { pump.activity = null; rxBus.send(new EventComboPumpUpdateGUI()); - rxBus.send(new EventRefreshOverview("Bolus")); + rxBus.send(new EventRefreshOverview("Bolus", false)); cancelBolus = false; } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java index a75398554e..bab8408935 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/insight/LocalInsightPlugin.java @@ -464,7 +464,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, lastUpdated = System.currentTimeMillis(); new Handler(Looper.getMainLooper()).post(() -> { rxBus.send(new EventLocalInsightUpdateGUI()); - rxBus.send(new EventRefreshOverview("LocalInsightPlugin::fetchStatus")); + rxBus.send(new EventRefreshOverview("LocalInsightPlugin::fetchStatus", false)); }); } @@ -1215,7 +1215,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, } catch (Exception e) { aapsLogger.error("Exception while reading history", e); } - new Handler(Looper.getMainLooper()).post(() -> rxBus.send(new EventRefreshOverview("LocalInsightPlugin::readHistory"))); + new Handler(Looper.getMainLooper()).post(() -> rxBus.send(new EventRefreshOverview("LocalInsightPlugin::readHistory", false))); } private void processHistoryEvents(String serial, List historyEvents) { @@ -1662,7 +1662,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface, activeTBR = null; activeBoluses = null; tbrOverNotificationBlock = null; - new Handler(Looper.getMainLooper()).post(() -> rxBus.send(new EventRefreshOverview("LocalInsightPlugin::onStateChanged"))); + new Handler(Looper.getMainLooper()).post(() -> rxBus.send(new EventRefreshOverview("LocalInsightPlugin::onStateChanged", false))); } new Handler(Looper.getMainLooper()).post(() -> rxBus.send(new EventLocalInsightUpdateGUI())); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java index 1c23665406..2f6c190179 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.java @@ -1073,7 +1073,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter private void finishAction(String overviewKey) { if (overviewKey != null) - rxBus.send(new EventRefreshOverview(overviewKey)); + rxBus.send(new EventRefreshOverview(overviewKey, false)); triggerUIChange(); diff --git a/app/src/main/java/info/nightscout/androidaps/utils/CryptoUtil.kt b/app/src/main/java/info/nightscout/androidaps/utils/CryptoUtil.kt index ad271e7344..e78b112615 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/CryptoUtil.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/CryptoUtil.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.utils +import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.utils.extensions.toHex import org.spongycastle.util.encoders.Base64 import java.nio.ByteBuffer @@ -13,16 +14,24 @@ import javax.crypto.SecretKeyFactory import javax.crypto.spec.GCMParameterSpec import javax.crypto.spec.PBEKeySpec import javax.crypto.spec.SecretKeySpec +import javax.inject.Inject +import javax.inject.Singleton -object CryptoUtil { +@Singleton +class CryptoUtil @Inject constructor( + val aapsLogger: AAPSLogger +) { - private const val IV_LENGTH_BYTE = 12 - private const val TAG_LENGTH_BIT = 128 - private const val AES_KEY_SIZE_BIT = 256 - private const val PBKDF2_ITERATIONS = 50000 // check delays it cause on real device - private const val SALT_SIZE_BYTE = 32 + companion object { + private const val IV_LENGTH_BYTE = 12 + private const val TAG_LENGTH_BIT = 128 + private const val AES_KEY_SIZE_BIT = 256 + private const val PBKDF2_ITERATIONS = 50000 // check delays it cause on real device + private const val SALT_SIZE_BYTE = 32 + } private val secureRandom: SecureRandom = SecureRandom() + var lastException: Exception? = null fun sha256(source: String): String { val digest = MessageDigest.getInstance("SHA-256") @@ -31,29 +40,30 @@ object CryptoUtil { } fun hmac256(str: String, secret: String): String? { - val sha256_HMAC = Mac.getInstance("HmacSHA256") + val sha256HMAC = Mac.getInstance("HmacSHA256") val secretKey = SecretKeySpec(secret.toByteArray(), "HmacSHA256") - sha256_HMAC.init(secretKey) - return sha256_HMAC.doFinal(str.toByteArray()).toHex() + sha256HMAC.init(secretKey) + return sha256HMAC.doFinal(str.toByteArray()).toHex() } - private fun prepCipherKey(passPhrase: String, salt:ByteArray, iterationCount:Int = PBKDF2_ITERATIONS, keyStrength:Int = AES_KEY_SIZE_BIT): SecretKeySpec { + private fun prepCipherKey(passPhrase: String, salt: ByteArray, iterationCount: Int = PBKDF2_ITERATIONS, keyStrength: Int = AES_KEY_SIZE_BIT): SecretKeySpec { val factory: SecretKeyFactory = SecretKeyFactory.getInstance("PBKDF2withHmacSHA1") val spec: KeySpec = PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount, keyStrength) val tmp: SecretKey = factory.generateSecret(spec) - return SecretKeySpec(tmp.getEncoded(), "AES") + return SecretKeySpec(tmp.encoded, "AES") } - fun mineSalt(len :Int = SALT_SIZE_BYTE): ByteArray { + fun mineSalt(len: Int = SALT_SIZE_BYTE): ByteArray { val salt = ByteArray(len) secureRandom.nextBytes(salt) return salt } - fun encrypt(passPhrase: String, salt:ByteArray, rawData: String ): String? { + fun encrypt(passPhrase: String, salt: ByteArray, rawData: String): String? { val iv: ByteArray? val encrypted: ByteArray? return try { + lastException = null iv = ByteArray(IV_LENGTH_BYTE) secureRandom.nextBytes(iv) val cipherEnc: Cipher = Cipher.getInstance("AES/GCM/NoPadding") @@ -65,14 +75,17 @@ object CryptoUtil { byteBuffer.put(encrypted) String(Base64.encode(byteBuffer.array())) } catch (e: Exception) { - null + lastException = e + aapsLogger.error("Encryption failed due to technical exception: $e") + null } } - fun decrypt(passPhrase: String, salt:ByteArray, encryptedData: String): String? { + fun decrypt(passPhrase: String, salt: ByteArray, encryptedData: String): String? { val iv: ByteArray? val encrypted: ByteArray? return try { + lastException = null val byteBuffer = ByteBuffer.wrap(Base64.decode(encryptedData)) val ivLength = byteBuffer.get().toInt() iv = ByteArray(ivLength) @@ -84,6 +97,8 @@ object CryptoUtil { val dec = cipherDec.doFinal(encrypted) String(dec) } catch (e: Exception) { + lastException = e + aapsLogger.error("Decryption failed due to technical exception: $e") null } } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/protection/PasswordCheck.kt b/app/src/main/java/info/nightscout/androidaps/utils/protection/PasswordCheck.kt index 1907ac01b5..2df55c9f2f 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/protection/PasswordCheck.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/protection/PasswordCheck.kt @@ -19,7 +19,10 @@ import javax.inject.Singleton val AUTOFILL_HINT_NEW_PASSWORD = "newPassword" @Singleton -class PasswordCheck @Inject constructor(val sp: SP) { +class PasswordCheck @Inject constructor( + val sp: SP, + val cryptoUtil: CryptoUtil +) { @SuppressLint("InflateParams") fun queryPassword(context: Context, @StringRes labelId: Int, @StringRes preference: Int, ok: ( (String) -> Unit)?, cancel: (()->Unit)? = null, fail: (()->Unit)? = null) { @@ -45,7 +48,7 @@ class PasswordCheck @Inject constructor(val sp: SP) { .setCustomTitle(AlertDialogHelper.buildCustomTitle(context, context.getString(labelId), R.drawable.ic_header_key)) .setPositiveButton(context.getString(R.string.ok)) { _, _ -> val enteredPassword = userInput.text.toString() - if (CryptoUtil.checkPassword(enteredPassword, password)) ok?.invoke(enteredPassword) + if (cryptoUtil.checkPassword(enteredPassword, password)) ok?.invoke(enteredPassword) else { ToastUtils.errorToast(context, context.getString(R.string.wrongpassword)) fail?.invoke() @@ -80,7 +83,7 @@ class PasswordCheck @Inject constructor(val sp: SP) { .setPositiveButton(context.getString(R.string.ok)) { _, _ -> val enteredPassword = userInput.text.toString() if (enteredPassword.isNotEmpty()) { - sp.putString(preference, CryptoUtil.hashPassword(enteredPassword)) + sp.putString(preference, cryptoUtil.hashPassword(enteredPassword)) ToastUtils.okToast(context, context.getString(R.string.password_set)) ok?.invoke(enteredPassword) } else { diff --git a/app/src/main/res/layout/insulin_fragment.xml b/app/src/main/res/layout/insulin_fragment.xml index 5f2a75850a..d1789ea80e 100644 --- a/app/src/main/res/layout/insulin_fragment.xml +++ b/app/src/main/res/layout/insulin_fragment.xml @@ -35,7 +35,7 @@ android:textAppearance="?android:attr/textAppearanceMedium" /> diff --git a/app/src/main/res/layout/overview_fragment.xml b/app/src/main/res/layout/overview_fragment.xml index 35ddd5eed4..64e32cf747 100644 --- a/app/src/main/res/layout/overview_fragment.xml +++ b/app/src/main/res/layout/overview_fragment.xml @@ -452,10 +452,11 @@ app:layout_constraintTop_toTopOf="@+id/overview_bggraph" /> - - - @@ -208,8 +208,8 @@ android:layout_height="wrap_content" android:layout_weight="0" android:gravity="center_horizontal" - android:paddingEnd="2dp" android:paddingStart="2dp" + android:paddingEnd="2dp" android:text=":" android:textSize="14sp" /> @@ -230,10 +230,10 @@ @@ -256,8 +256,8 @@ android:layout_height="wrap_content" android:layout_weight="0" android:gravity="center_horizontal" - android:paddingEnd="2dp" android:paddingStart="2dp" + android:paddingEnd="2dp" android:text=":" android:textSize="14sp" /> @@ -278,10 +278,10 @@ @@ -304,8 +304,8 @@ android:layout_height="wrap_content" android:layout_weight="0" android:gravity="center_horizontal" - android:paddingEnd="2dp" android:paddingStart="2dp" + android:paddingEnd="2dp" android:text=":" android:textSize="14sp" /> @@ -326,10 +326,10 @@ @@ -373,10 +373,10 @@ @@ -425,10 +425,10 @@ @@ -454,10 +454,10 @@ @@ -512,8 +512,8 @@ android:id="@+id/overview_chartMenuButton" android:layout_width="30dp" android:layout_height="wrap_content" - android:layout_alignParentEnd="true" android:layout_alignParentTop="true" + android:layout_alignParentEnd="true" android:paddingTop="5dp" app:srcCompat="@drawable/ic_arrow_drop_down_white_24dp" /> @@ -526,10 +526,11 @@ - + android:layout_height="wrap_content" + android:orientation="vertical" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f145dd5b56..f6d094acdc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1813,4 +1813,7 @@ Invalid pairing information. Requesting new pairing On connect On disconnect + Predictions + Deviation slope + graphconfig diff --git a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt index 545b8fc119..94ebceece5 100644 --- a/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/interfaces/ConstraintsCheckerTest.kt @@ -7,7 +7,6 @@ import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.R import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin -import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker @@ -44,7 +43,7 @@ import java.util.* * Created by mike on 18.03.2018. */ @RunWith(PowerMockRunner::class) -@PrepareForTest(MainApp::class, ConfigBuilderPlugin::class, ConstraintChecker::class, SP::class, Context::class, OpenAPSMAPlugin::class, OpenAPSAMAPlugin::class, OpenAPSSMBPlugin::class, TreatmentsPlugin::class, TreatmentService::class, VirtualPumpPlugin::class, DetailedBolusInfoStorage::class, GlimpPlugin::class) +@PrepareForTest(MainApp::class, ConfigBuilderPlugin::class, ConstraintChecker::class, SP::class, Context::class, OpenAPSAMAPlugin::class, OpenAPSSMBPlugin::class, TreatmentsPlugin::class, TreatmentService::class, VirtualPumpPlugin::class, DetailedBolusInfoStorage::class, GlimpPlugin::class) class ConstraintsCheckerTest : TestBaseWithProfile() { @Mock lateinit var activePlugin: ActivePluginProvider @@ -70,7 +69,6 @@ class ConstraintsCheckerTest : TestBaseWithProfile() { private lateinit var insightPlugin: LocalInsightPlugin private lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin private lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin - private lateinit var openAPSMAPlugin: OpenAPSMAPlugin private lateinit var hardLimits: HardLimits val injector = HasAndroidInjector { @@ -119,8 +117,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() { insightPlugin = LocalInsightPlugin(injector, aapsLogger, rxBus, resourceHelper, treatmentsPlugin, sp, commandQueue, profileFunction, context) openAPSSMBPlugin = OpenAPSSMBPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsPlugin, iobCobCalculatorPlugin, hardLimits) openAPSAMAPlugin = OpenAPSAMAPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsPlugin, iobCobCalculatorPlugin, hardLimits) - openAPSMAPlugin = OpenAPSMAPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsPlugin, iobCobCalculatorPlugin, hardLimits) - safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, treatmentsPlugin) + safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, treatmentsPlugin) val constraintsPluginsList = ArrayList() constraintsPluginsList.add(safetyPlugin) constraintsPluginsList.add(objectivesPlugin) @@ -316,7 +313,6 @@ class ConstraintsCheckerTest : TestBaseWithProfile() { `when`(sp.getDouble(R.string.key_openapsma_max_iob, 1.5)).thenReturn(1.5) `when`(sp.getString(R.string.key_age, "")).thenReturn("teenage") openAPSAMAPlugin.setPluginEnabled(PluginType.APS, true) - openAPSMAPlugin.setPluginEnabled(PluginType.APS, false) openAPSSMBPlugin.setPluginEnabled(PluginType.APS, false) // Apply all limits @@ -333,7 +329,6 @@ class ConstraintsCheckerTest : TestBaseWithProfile() { `when`(sp.getString(R.string.key_age, "")).thenReturn("teenage") openAPSSMBPlugin.setPluginEnabled(PluginType.APS, true) openAPSAMAPlugin.setPluginEnabled(PluginType.APS, false) - openAPSMAPlugin.setPluginEnabled(PluginType.APS, false) // Apply all limits val d = constraintChecker.getMaxIOBAllowed() diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPluginTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPluginTest.kt index c3e4b8a01f..9da162a301 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPluginTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/constraints/safety/SafetyPluginTest.kt @@ -10,7 +10,6 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.PumpDescription import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin -import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin @@ -35,7 +34,6 @@ class SafetyPluginTest : TestBaseWithProfile() { @Mock lateinit var sp: SP @Mock lateinit var constraintChecker: ConstraintChecker @Mock lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin - @Mock lateinit var openAPSMAPlugin: OpenAPSMAPlugin @Mock lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin @Mock lateinit var sensitivityOref1Plugin: SensitivityOref1Plugin @Mock lateinit var activePlugin: ActivePluginProvider @@ -75,7 +73,7 @@ class SafetyPluginTest : TestBaseWithProfile() { `when`(activePlugin.activePump).thenReturn(virtualPumpPlugin) `when`(virtualPumpPlugin.pumpDescription).thenReturn(pumpDescription) hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context) - safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, treatmentsPlugin) + safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, treatmentsPlugin) } @Test fun pumpDescriptionShouldLimitLoopInvocation() { diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/EncryptedPrefsFormatTest.kt b/app/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/EncryptedPrefsFormatTest.kt index 16c2f4b0ef..4537783ce4 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/EncryptedPrefsFormatTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/maintenance/EncryptedPrefsFormatTest.kt @@ -5,10 +5,11 @@ import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.plugins.general.maintenance.formats.* import info.nightscout.androidaps.testing.mockers.AAPSMocker import info.nightscout.androidaps.testing.utils.SingleStringStorage +import info.nightscout.androidaps.utils.CryptoUtil +import info.nightscout.androidaps.utils.assumeAES256isSupported import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.sharedPreferences.SP import org.hamcrest.CoreMatchers -import org.json.JSONException import org.junit.Assert import org.junit.Before import org.junit.Test @@ -30,6 +31,8 @@ class EncryptedPrefsFormatTest : TestBase() { @Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var sp: SP + var cryptoUtil: CryptoUtil = CryptoUtil(aapsLogger) + @Before fun mock() { AAPSMocker.prepareMock() @@ -52,9 +55,11 @@ class EncryptedPrefsFormatTest : TestBase() { "}" val storage = SingleStringStorage(frozenPrefs) - val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) + val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage) val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") + assumeAES256isSupported(cryptoUtil) + Assert.assertThat(prefs.values.size, CoreMatchers.`is`(2)) Assert.assertThat(prefs.values["key1"], CoreMatchers.`is`("A")) Assert.assertThat(prefs.values["keyB"], CoreMatchers.`is`("2")) @@ -67,7 +72,7 @@ class EncryptedPrefsFormatTest : TestBase() { @Test fun preferenceSavingTest() { val storage = SingleStringStorage("") - val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) + val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage) val prefs = Prefs( mapOf( "key1" to "A", @@ -84,7 +89,7 @@ class EncryptedPrefsFormatTest : TestBase() { @Test fun importExportStabilityTest() { val storage = SingleStringStorage("") - val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) + val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage) val prefsIn = Prefs( mapOf( "testpref1" to "--1--", @@ -97,6 +102,8 @@ class EncryptedPrefsFormatTest : TestBase() { encryptedFormat.savePreferences(AAPSMocker.getMockedFile(), prefsIn, "tajemnica") val prefsOut = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "tajemnica") + assumeAES256isSupported(cryptoUtil) + Assert.assertThat(prefsOut.values.size, CoreMatchers.`is`(2)) Assert.assertThat(prefsOut.values["testpref1"], CoreMatchers.`is`("--1--")) Assert.assertThat(prefsOut.values["testpref2"], CoreMatchers.`is`("another")) @@ -121,7 +128,7 @@ class EncryptedPrefsFormatTest : TestBase() { "}" val storage = SingleStringStorage(frozenPrefs) - val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) + val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage) val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "it-is-NOT-right-secret") Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0)) @@ -148,9 +155,11 @@ class EncryptedPrefsFormatTest : TestBase() { "}" val storage = SingleStringStorage(frozenPrefs) - val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) + val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage) val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") + assumeAES256isSupported(cryptoUtil) + // contents were not tampered and we can decrypt them Assert.assertThat(prefs.values.size, CoreMatchers.`is`(2)) @@ -173,7 +182,7 @@ class EncryptedPrefsFormatTest : TestBase() { "}" val storage = SingleStringStorage(frozenPrefs) - val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) + val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage) val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0)) @@ -188,7 +197,7 @@ class EncryptedPrefsFormatTest : TestBase() { "}" val storage = SingleStringStorage(frozenPrefs) - val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) + val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage) val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0)) @@ -200,7 +209,7 @@ class EncryptedPrefsFormatTest : TestBase() { val frozenPrefs = "whatever man, i duno care" val storage = SingleStringStorage(frozenPrefs) - val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) + val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage) encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") } @@ -219,7 +228,7 @@ class EncryptedPrefsFormatTest : TestBase() { "}" val storage = SingleStringStorage(frozenPrefs) - val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) + val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage) encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") } diff --git a/app/src/test/java/info/nightscout/androidaps/utils/CryptoUtilTest.kt b/app/src/test/java/info/nightscout/androidaps/utils/CryptoUtilTest.kt index c147c0810c..9d6b3ad9cd 100644 --- a/app/src/test/java/info/nightscout/androidaps/utils/CryptoUtilTest.kt +++ b/app/src/test/java/info/nightscout/androidaps/utils/CryptoUtilTest.kt @@ -1,16 +1,31 @@ package info.nightscout.androidaps.utils import info.nightscout.androidaps.TestBase +import org.hamcrest.CoreMatchers.containsString +import org.hamcrest.CoreMatchers.not import org.junit.Assert +import org.junit.Assume.assumeThat import org.junit.Test import org.junit.runner.RunWith import org.powermock.core.classloader.annotations.PowerMockIgnore import org.powermock.modules.junit4.PowerMockRunner +// https://stackoverflow.com/questions/52344522/joseexception-couldnt-create-aes-gcm-nopadding-cipher-illegal-key-size +// https://stackoverflow.com/questions/47708951/can-aes-256-work-on-android-devices-with-api-level-26 +// Java prior to Oracle Java 8u161 does not have policy for 256 bit AES - but Android support it +// when test is run in Vanilla JVM without policy - Invalid key size exception is thrown +fun assumeAES256isSupported(cryptoUtil: CryptoUtil) { + cryptoUtil.lastException?.message?.let { exceptionMessage -> + assumeThat("Upgrade your testing environment Java (OpenJDK or Java 8u161) and JAVA_HOME - AES 256 is supported by Android so this exception should not happen!", exceptionMessage, not(containsString("key size"))) + } +} + @PowerMockIgnore("javax.crypto.*") @RunWith(PowerMockRunner::class) class CryptoUtilTest: TestBase() { + var cryptoUtil: CryptoUtil = CryptoUtil(aapsLogger) + @Test fun testFixedSaltCrypto() { val salt = byteArrayOf( @@ -19,30 +34,36 @@ class CryptoUtilTest: TestBase() { val password = "thisIsFixedPassword" val payload = "FIXED-PAYLOAD" - val encrypted = CryptoUtil.encrypt(password, salt, payload) + val encrypted = cryptoUtil.encrypt(password, salt, payload) + assumeAES256isSupported(cryptoUtil) Assert.assertNotNull(encrypted) - val decrypted = CryptoUtil.decrypt(password, salt, encrypted!!) + + val decrypted = cryptoUtil.decrypt(password, salt, encrypted!!) + assumeAES256isSupported(cryptoUtil) Assert.assertEquals(decrypted, payload) } @Test fun testStandardCrypto() { - val salt = CryptoUtil.mineSalt() + val salt = cryptoUtil.mineSalt() val password = "topSikret" val payload = "{what:payloadYouWantToProtect}" - val encrypted = CryptoUtil.encrypt(password, salt, payload) + val encrypted = cryptoUtil.encrypt(password, salt, payload) + assumeAES256isSupported(cryptoUtil) Assert.assertNotNull(encrypted) - val decrypted = CryptoUtil.decrypt(password, salt, encrypted!!) + + val decrypted = cryptoUtil.decrypt(password, salt, encrypted!!) + assumeAES256isSupported(cryptoUtil) Assert.assertEquals(decrypted, payload) } @Test fun testHashVector() { val payload = "{what:payloadYouWantToProtect}" - val hash = CryptoUtil.sha256(payload) + val hash = cryptoUtil.sha256(payload) Assert.assertEquals(hash, "a1aafe3ed6cc127e6d102ddbc40a205147230e9cfd178daf108c83543bbdcd13") } @@ -51,25 +72,25 @@ class CryptoUtilTest: TestBase() { val payload = "{what:payloadYouWantToProtect}" val password = "topSikret" val expectedHmac = "ea2213953d0f2e55047cae2d23fb4f0de1b805d55e6271efa70d6b85fb692bea" // generated using other HMAC tool - val hash = CryptoUtil.hmac256(payload, password) + val hash = cryptoUtil.hmac256(payload, password) Assert.assertEquals(hash, expectedHmac) } @Test fun testPlainPasswordCheck() { - Assert.assertTrue(CryptoUtil.checkPassword("same", "same")) - Assert.assertFalse(CryptoUtil.checkPassword("same", "other")) + Assert.assertTrue(cryptoUtil.checkPassword("same", "same")) + Assert.assertFalse(cryptoUtil.checkPassword("same", "other")) } @Test fun testHashedPasswordCheck() { - Assert.assertTrue(CryptoUtil.checkPassword("givenSecret", CryptoUtil.hashPassword("givenSecret"))) - Assert.assertFalse(CryptoUtil.checkPassword("givenSecret", CryptoUtil.hashPassword("otherSecret"))) + Assert.assertTrue(cryptoUtil.checkPassword("givenSecret", cryptoUtil.hashPassword("givenSecret"))) + Assert.assertFalse(cryptoUtil.checkPassword("givenSecret", cryptoUtil.hashPassword("otherSecret"))) - Assert.assertTrue(CryptoUtil.checkPassword("givenHashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1")) - Assert.assertFalse(CryptoUtil.checkPassword("givenMashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1")) - Assert.assertFalse(CryptoUtil.checkPassword("givenHashToCheck", "hmac:0fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1")) - Assert.assertFalse(CryptoUtil.checkPassword("givenHashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:b0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1")) + Assert.assertTrue(cryptoUtil.checkPassword("givenHashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1")) + Assert.assertFalse(cryptoUtil.checkPassword("givenMashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1")) + Assert.assertFalse(cryptoUtil.checkPassword("givenHashToCheck", "hmac:0fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1")) + Assert.assertFalse(cryptoUtil.checkPassword("givenHashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:b0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1")) } }