Merge remote-tracking branch 'origin/dagger3' into rs

This commit is contained in:
Milos Kozak 2020-04-07 13:15:06 +02:00
commit 453a55db7b
43 changed files with 333 additions and 1263 deletions

View file

@ -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;

View file

@ -19,7 +19,6 @@ import info.nightscout.androidaps.events.EventRebuildTabs
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin 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.aps.openAPSSMB.OpenAPSSMBPlugin
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.PluginStore import info.nightscout.androidaps.plugins.configBuilder.PluginStore
@ -80,7 +79,6 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
@Inject lateinit var medtronicPumpPlugin: MedtronicPumpPlugin @Inject lateinit var medtronicPumpPlugin: MedtronicPumpPlugin
@Inject lateinit var nsClientPlugin: NSClientPlugin @Inject lateinit var nsClientPlugin: NSClientPlugin
@Inject lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin @Inject lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin
@Inject lateinit var openAPSMAPlugin: OpenAPSMAPlugin
@Inject lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin @Inject lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin
@Inject lateinit var safetyPlugin: SafetyPlugin @Inject lateinit var safetyPlugin: SafetyPlugin
@Inject lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin @Inject lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin
@ -162,7 +160,6 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
addPreferencesFromResourceIfEnabled(glimpPlugin, rootKey) addPreferencesFromResourceIfEnabled(glimpPlugin, rootKey)
addPreferencesFromResourceIfEnabled(careportalPlugin, rootKey) addPreferencesFromResourceIfEnabled(careportalPlugin, rootKey)
addPreferencesFromResourceIfEnabled(loopPlugin, rootKey, Config.APS) addPreferencesFromResourceIfEnabled(loopPlugin, rootKey, Config.APS)
addPreferencesFromResourceIfEnabled(openAPSMAPlugin, rootKey, Config.APS)
addPreferencesFromResourceIfEnabled(openAPSAMAPlugin, rootKey, Config.APS) addPreferencesFromResourceIfEnabled(openAPSAMAPlugin, rootKey, Config.APS)
addPreferencesFromResourceIfEnabled(openAPSSMBPlugin, rootKey, Config.APS) addPreferencesFromResourceIfEnabled(openAPSSMBPlugin, rootKey, Config.APS)
addPreferencesFromResourceIfEnabled(sensitivityAAPSPlugin, rootKey) addPreferencesFromResourceIfEnabled(sensitivityAAPSPlugin, rootKey)

View file

@ -234,7 +234,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
new java.util.TimerTask() { new java.util.TimerTask() {
@Override @Override
public void run() { public void run() {
RxBus.Companion.getINSTANCE().send(new EventRefreshOverview("resetDatabases")); RxBus.Companion.getINSTANCE().send(new EventRefreshOverview("resetDatabases", false));
} }
}, },
3000 3000

View file

@ -12,8 +12,7 @@ import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.db.ProfileSwitch import info.nightscout.androidaps.db.ProfileSwitch
import info.nightscout.androidaps.plugins.aps.loop.APSResult import info.nightscout.androidaps.plugins.aps.loop.APSResult
import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalResultAMA import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalResultAMA
import info.nightscout.androidaps.plugins.aps.openAPSMA.DetermineBasalResultMA import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
import info.nightscout.androidaps.plugins.aps.openAPSMA.LoggerCallback
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.* import info.nightscout.androidaps.plugins.constraints.objectives.objectives.*
@ -55,7 +54,6 @@ interface AppComponent : AndroidInjector<MainApp> {
fun injectPumpEnactResult(pumpEnactResult: PumpEnactResult) fun injectPumpEnactResult(pumpEnactResult: PumpEnactResult)
fun injectAPSResult(apsResult: APSResult) fun injectAPSResult(apsResult: APSResult)
fun injectDetermineBasalResultSMB(determineBasalResultSMB: DetermineBasalResultSMB) fun injectDetermineBasalResultSMB(determineBasalResultSMB: DetermineBasalResultSMB)
fun injectDetermineBasalResultMA(determineBasalResultMA: DetermineBasalResultMA)
fun injectDetermineBasalResultAMA(determineBasalResultAMA: DetermineBasalResultAMA) fun injectDetermineBasalResultAMA(determineBasalResultAMA: DetermineBasalResultAMA)
fun injectDetermineBasalAdapterSMBJS(determineBasalAdapterSMBJS: DetermineBasalAdapterSMBJS) fun injectDetermineBasalAdapterSMBJS(determineBasalAdapterSMBJS: DetermineBasalAdapterSMBJS)

View file

@ -22,8 +22,7 @@ import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.AAPSLoggerProduction import info.nightscout.androidaps.logging.AAPSLoggerProduction
import info.nightscout.androidaps.plugins.aps.loop.APSResult import info.nightscout.androidaps.plugins.aps.loop.APSResult
import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalResultAMA import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalResultAMA
import info.nightscout.androidaps.plugins.aps.openAPSMA.DetermineBasalResultMA import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
import info.nightscout.androidaps.plugins.aps.openAPSMA.LoggerCallback
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB
import info.nightscout.androidaps.plugins.configBuilder.PluginStore 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.SWEventListener
import info.nightscout.androidaps.setupwizard.SWScreen import info.nightscout.androidaps.setupwizard.SWScreen
import info.nightscout.androidaps.setupwizard.elements.* import info.nightscout.androidaps.setupwizard.elements.*
import info.nightscout.androidaps.utils.CryptoUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.resources.ResourceHelperImplementation import info.nightscout.androidaps.utils.resources.ResourceHelperImplementation
@ -121,7 +121,6 @@ open class AppModule {
@ContributesAndroidInjector fun apsResultInjector(): APSResult @ContributesAndroidInjector fun apsResultInjector(): APSResult
@ContributesAndroidInjector fun determineBasalResultSMBInjector(): DetermineBasalResultSMB @ContributesAndroidInjector fun determineBasalResultSMBInjector(): DetermineBasalResultSMB
@ContributesAndroidInjector fun determineBasalResultMAInjector(): DetermineBasalResultMA
@ContributesAndroidInjector fun determineBasalResultAMAInjector(): DetermineBasalResultAMA @ContributesAndroidInjector fun determineBasalResultAMAInjector(): DetermineBasalResultAMA
@ContributesAndroidInjector @ContributesAndroidInjector
@ -261,6 +260,7 @@ open class AppModule {
@ContributesAndroidInjector fun graphDataInjector(): GraphData @ContributesAndroidInjector fun graphDataInjector(): GraphData
@ContributesAndroidInjector fun cryptoUtilInjector(): CryptoUtil
@ContributesAndroidInjector fun importExportPrefsInjector(): ImportExportPrefs @ContributesAndroidInjector fun importExportPrefsInjector(): ImportExportPrefs
@ContributesAndroidInjector fun encryptedPrefsFormatInjector(): EncryptedPrefsFormat @ContributesAndroidInjector fun encryptedPrefsFormatInjector(): EncryptedPrefsFormat
@ContributesAndroidInjector fun classicPrefsFormatInjector(): ClassicPrefsFormat @ContributesAndroidInjector fun classicPrefsFormatInjector(): ClassicPrefsFormat

View file

@ -6,7 +6,6 @@ import info.nightscout.androidaps.activities.MyPreferenceFragment
import info.nightscout.androidaps.dialogs.* import info.nightscout.androidaps.dialogs.*
import info.nightscout.androidaps.plugins.aps.loop.LoopFragment import info.nightscout.androidaps.plugins.aps.loop.LoopFragment
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAFragment 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.aps.openAPSSMB.OpenAPSSMBFragment
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderFragment import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderFragment
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesFragment import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesFragment
@ -64,7 +63,6 @@ abstract class FragmentsModule {
@ContributesAndroidInjector abstract fun contributesLocalProfileFragment(): LocalProfileFragment @ContributesAndroidInjector abstract fun contributesLocalProfileFragment(): LocalProfileFragment
@ContributesAndroidInjector abstract fun contributesObjectivesFragment(): ObjectivesFragment @ContributesAndroidInjector abstract fun contributesObjectivesFragment(): ObjectivesFragment
@ContributesAndroidInjector abstract fun contributesOpenAPSAMAFragment(): OpenAPSAMAFragment @ContributesAndroidInjector abstract fun contributesOpenAPSAMAFragment(): OpenAPSAMAFragment
@ContributesAndroidInjector abstract fun contributesOpenAPSMAFragment(): OpenAPSMAFragment
@ContributesAndroidInjector abstract fun contributesOpenAPSSMBFragment(): OpenAPSSMBFragment @ContributesAndroidInjector abstract fun contributesOpenAPSSMBFragment(): OpenAPSSMBFragment
@ContributesAndroidInjector abstract fun contributesOverviewFragment(): OverviewFragment @ContributesAndroidInjector abstract fun contributesOverviewFragment(): OverviewFragment
@ContributesAndroidInjector abstract fun contributesLocalInsightFragment(): LocalInsightFragment @ContributesAndroidInjector abstract fun contributesLocalInsightFragment(): LocalInsightFragment

View file

@ -11,7 +11,6 @@ import info.nightscout.androidaps.Config
import info.nightscout.androidaps.interfaces.PluginBase import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin 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.aps.openAPSSMB.OpenAPSSMBPlugin
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.constraints.dstHelper.DstHelperPlugin import info.nightscout.androidaps.plugins.constraints.dstHelper.DstHelperPlugin
@ -188,36 +187,30 @@ abstract class PluginsModule {
@APS @APS
@IntoMap @IntoMap
@IntKey(210) @IntKey(210)
abstract fun bindOpenAPSMAPlugin(plugin: OpenAPSMAPlugin): PluginBase
@Binds
@APS
@IntoMap
@IntKey(220)
abstract fun bindOpenAPSAMAPlugin(plugin: OpenAPSAMAPlugin): PluginBase abstract fun bindOpenAPSAMAPlugin(plugin: OpenAPSAMAPlugin): PluginBase
@Binds @Binds
@APS @APS
@IntoMap @IntoMap
@IntKey(230) @IntKey(220)
abstract fun bindOpenAPSSMBPlugin(plugin: OpenAPSSMBPlugin): PluginBase abstract fun bindOpenAPSSMBPlugin(plugin: OpenAPSSMBPlugin): PluginBase
@Binds @Binds
@AllConfigs @AllConfigs
@IntoMap @IntoMap
@IntKey(240) @IntKey(230)
abstract fun bindNSProfilePlugin(plugin: NSProfilePlugin): PluginBase abstract fun bindNSProfilePlugin(plugin: NSProfilePlugin): PluginBase
@Binds @Binds
@NotNSClient @NotNSClient
@IntoMap @IntoMap
@IntKey(250) @IntKey(240)
abstract fun bindLocalProfilePlugin(plugin: LocalProfilePlugin): PluginBase abstract fun bindLocalProfilePlugin(plugin: LocalProfilePlugin): PluginBase
@Binds @Binds
@AllConfigs @AllConfigs
@IntoMap @IntoMap
@IntKey(255) @IntKey(250)
abstract fun bindAutomationPlugin(plugin: AutomationPlugin): PluginBase abstract fun bindAutomationPlugin(plugin: AutomationPlugin): PluginBase
@Binds @Binds

View file

@ -1,3 +1,3 @@
package info.nightscout.androidaps.events package info.nightscout.androidaps.events
class EventRefreshOverview(var from: String) : Event() class EventRefreshOverview(var from: String, val now : Boolean = false) : Event()

View file

@ -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 import info.nightscout.androidaps.events.EventUpdateGui

View file

@ -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 import info.nightscout.androidaps.events.EventUpdateGui

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.plugins.aps.openAPSMA; package info.nightscout.androidaps.plugins.aps.logger;
import org.mozilla.javascript.ScriptableObject; import org.mozilla.javascript.ScriptableObject;

View file

@ -29,7 +29,7 @@ import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader; 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.aps.openAPSSMB.SMBDefaults;
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;

View file

@ -9,8 +9,8 @@ import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy

View file

@ -23,8 +23,8 @@ import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.loop.APSResult; import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader; import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui; import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui;
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui; import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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 = ""
}
}

View file

@ -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());
}
}

View file

@ -29,7 +29,7 @@ import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader; 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.ConstraintChecker;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus; import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;

View file

@ -10,8 +10,8 @@ import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui
import info.nightscout.androidaps.plugins.bus.RxBusWrapper import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy

View file

@ -26,8 +26,8 @@ import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.logging.LTag;
import info.nightscout.androidaps.plugins.aps.loop.APSResult; import info.nightscout.androidaps.plugins.aps.loop.APSResult;
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader; import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui; import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui;
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui; import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;

View file

@ -20,7 +20,6 @@ import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.AAPSLogger;
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin; 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.aps.openAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker; import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
@ -42,7 +41,6 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
private RxBusWrapper rxBus; private RxBusWrapper rxBus;
private ConstraintChecker constraintChecker; private ConstraintChecker constraintChecker;
private OpenAPSAMAPlugin openAPSAMAPlugin; private OpenAPSAMAPlugin openAPSAMAPlugin;
private OpenAPSMAPlugin openAPSMAPlugin;
private OpenAPSSMBPlugin openAPSSMBPlugin; private OpenAPSSMBPlugin openAPSSMBPlugin;
private SensitivityOref1Plugin sensitivityOref1Plugin; private SensitivityOref1Plugin sensitivityOref1Plugin;
private ActivePluginProvider activePlugin; private ActivePluginProvider activePlugin;
@ -59,7 +57,6 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
RxBusWrapper rxBus, RxBusWrapper rxBus,
ConstraintChecker constraintChecker, ConstraintChecker constraintChecker,
OpenAPSAMAPlugin openAPSAMAPlugin, OpenAPSAMAPlugin openAPSAMAPlugin,
OpenAPSMAPlugin openAPSMAPlugin,
OpenAPSSMBPlugin openAPSSMBPlugin, OpenAPSSMBPlugin openAPSSMBPlugin,
SensitivityOref1Plugin sensitivityOref1Plugin, SensitivityOref1Plugin sensitivityOref1Plugin,
ActivePluginProvider activePlugin, ActivePluginProvider activePlugin,
@ -80,7 +77,6 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
this.rxBus = rxBus; this.rxBus = rxBus;
this.constraintChecker = constraintChecker; this.constraintChecker = constraintChecker;
this.openAPSAMAPlugin = openAPSAMAPlugin; this.openAPSAMAPlugin = openAPSAMAPlugin;
this.openAPSMAPlugin = openAPSMAPlugin;
this.openAPSSMBPlugin = openAPSSMBPlugin; this.openAPSSMBPlugin = openAPSSMBPlugin;
this.sensitivityOref1Plugin = sensitivityOref1Plugin; this.sensitivityOref1Plugin = sensitivityOref1Plugin;
this.activePlugin = activePlugin; 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); 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); 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)) 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); 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)) if (openAPSSMBPlugin.isEnabled(PluginType.APS))

View file

@ -22,7 +22,7 @@ import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin 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.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus

View file

@ -18,6 +18,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class EncryptedPrefsFormat @Inject constructor( class EncryptedPrefsFormat @Inject constructor(
private var resourceHelper: ResourceHelper, private var resourceHelper: ResourceHelper,
private var cryptoUtil: CryptoUtil,
private var storage: Storage private var storage: Storage
) : PrefsFormat { ) : PrefsFormat {
@ -58,14 +59,14 @@ class EncryptedPrefsFormat @Inject constructor(
var encodedContent = "" var encodedContent = ""
if (encrypted) { if (encrypted) {
val salt = CryptoUtil.mineSalt() val salt = cryptoUtil.mineSalt()
val rawContent = content.toString() val rawContent = content.toString()
val contentAttempt = CryptoUtil.encrypt(masterPassword!!, salt, rawContent) val contentAttempt = cryptoUtil.encrypt(masterPassword!!, salt, rawContent)
if (contentAttempt != null) { if (contentAttempt != null) {
encodedContent = contentAttempt encodedContent = contentAttempt
security.put("algorithm", "v1") security.put("algorithm", "v1")
security.put("salt", salt.toHex()) security.put("salt", salt.toHex())
security.put("content_hash", CryptoUtil.sha256(rawContent)) security.put("content_hash", cryptoUtil.sha256(rawContent))
} else { } else {
// fallback when encryption does not work // fallback when encryption does not work
encrypted = false encrypted = false
@ -80,7 +81,7 @@ class EncryptedPrefsFormat @Inject constructor(
container.put("content", if (encrypted) encodedContent else content) container.put("content", if (encrypted) encodedContent else content)
var fileContents = container.toString(2) 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") 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 jsonBody = storage.getFileContents(file)
val fileContents = jsonBody.replace(Regex("(?is)(\\\"file_hash\\\"\\s*\\:\\s*\\\")([^\"]*)(\\\")"), "$1--to-be-calculated--$3") 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) val container = JSONObject(jsonBody)
if (container.has(PrefsMetadataKey.FILE_FORMAT.key) && container.has("security") && container.has("content") && container.has("metadata")) { 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")) { if (security.has("salt") && security.has("content_hash")) {
val salt = security.getString("salt").hexStringToByteArray() 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) { if (decrypted != null) {
try { try {
val contentHash = CryptoUtil.sha256(decrypted) val contentHash = cryptoUtil.sha256(decrypted)
if (contentHash == security.getString("content_hash")) { if (contentHash == security.getString("content_hash")) {
contentJsonObj = JSONObject(decrypted) contentJsonObj = JSONObject(decrypted)

View file

@ -5,6 +5,7 @@ import android.app.NotificationManager
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Color
import android.graphics.Paint import android.graphics.Paint
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
@ -17,7 +18,9 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.View.OnLongClickListener import android.view.View.OnLongClickListener
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.jjoe64.graphview.GraphView
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.Config import info.nightscout.androidaps.Config
@ -93,6 +96,7 @@ import java.util.concurrent.Executors
import java.util.concurrent.ScheduledFuture import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
import kotlin.collections.ArrayList
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.max import kotlin.math.max
@ -130,6 +134,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
private var smallWidth = false private var smallWidth = false
private var smallHeight = false private var smallHeight = false
private lateinit var dm: DisplayMetrics private lateinit var dm: DisplayMetrics
private var axisWidth: Int = 0
private var rangeToDisplay = 6 // for graph private var rangeToDisplay = 6 // for graph
private var loopHandler = Handler() private var loopHandler = Handler()
private var refreshLoop: Runnable? = null private var refreshLoop: Runnable? = null
@ -137,6 +142,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
private val worker = Executors.newSingleThreadScheduledExecutor() private val worker = Executors.newSingleThreadScheduledExecutor()
private var scheduledUpdate: ScheduledFuture<*>? = null private var scheduledUpdate: ScheduledFuture<*>? = null
private val secondaryGraphs = ArrayList<GraphView>()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View? {
@ -173,15 +180,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
overview_notifications?.setHasFixedSize(false) overview_notifications?.setHasFixedSize(false)
overview_notifications?.layoutManager = LinearLayoutManager(view.context) 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?.gridColor = resourceHelper.gc(R.color.graphgrid)
overview_bggraph?.gridLabelRenderer?.reloadStyles() 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_bggraph?.gridLabelRenderer?.labelVerticalWidth = axisWidth
overview_iobgraph?.gridLabelRenderer?.labelVerticalWidth = axisWidth
overview_iobgraph?.gridLabelRenderer?.numVerticalLabels = 3
rangeToDisplay = sp.getInt(R.string.key_rangetodisplay, 6) rangeToDisplay = sp.getInt(R.string.key_rangetodisplay, 6)
overview_bggraph?.setOnLongClickListener { overview_bggraph?.setOnLongClickListener {
@ -193,6 +196,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
false false
} }
overviewMenus.setupChartMenu(overview_chartMenuButton) overviewMenus.setupChartMenu(overview_chartMenuButton)
prepareGraphs()
overview_accepttempbutton?.setOnClickListener(this) overview_accepttempbutton?.setOnClickListener(this)
overview_treatmentbutton?.setOnClickListener(this) overview_treatmentbutton?.setOnClickListener(this)
@ -218,8 +222,12 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
super.onResume() super.onResume()
disposable.add(rxBus disposable.add(rxBus
.toObservable(EventRefreshOverview::class.java) .toObservable(EventRefreshOverview::class.java)
.observeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ scheduleUpdateGUI(it.from) }) { fabricPrivacy.logException(it) }) .subscribe({
prepareGraphs()
if (it.now) updateGUI(it.from)
else scheduleUpdateGUI(it.from)
}) { fabricPrivacy.logException(it) })
disposable.add(rxBus disposable.add(rxBus
.toObservable(EventExtendedBolusChange::class.java) .toObservable(EventExtendedBolusChange::class.java)
.observeOn(Schedulers.io()) .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) { private fun scheduleUpdateGUI(from: String) {
class UpdateRunnable : Runnable { class UpdateRunnable : Runnable {
override fun run() { override fun run() {
@ -746,19 +778,20 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
graphData.addInRangeArea(fromTime, endTime, lowLine, highLine) graphData.addInRangeArea(fromTime, endTime, lowLine, highLine)
// **** BG **** // **** BG ****
if (predictionsAvailable && sp.getBoolean("showprediction", false)) graphData.addBgReadings(fromTime, toTime, lowLine, highLine, if (predictionsAvailable && overviewMenus.setting[0][OverviewMenus.CharType.PRE.ordinal])
apsResult?.predictions) else graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null) graphData.addBgReadings(fromTime, toTime, lowLine, highLine, apsResult?.predictions)
else graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null)
// set manual x bounds to have nice steps // set manual x bounds to have nice steps
graphData.formatAxis(fromTime, endTime) graphData.formatAxis(fromTime, endTime)
// Treatments // Treatments
graphData.addTreatments(fromTime, endTime) graphData.addTreatments(fromTime, endTime)
if (sp.getBoolean("showactivityprimary", true)) if (overviewMenus.setting[0][OverviewMenus.CharType.ACT.ordinal])
graphData.addActivity(fromTime, endTime, false, 0.8) graphData.addActivity(fromTime, endTime, false, 0.8)
// add basal data // 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) graphData.addBasals(fromTime, now, lowLine / graphData.maxY / 1.2)
// add target line // add target line
@ -768,57 +801,53 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
graphData.addNowLine(now) graphData.addNowLine(now)
// ------------------ 2nd graph // ------------------ 2nd graph
val secondGraphData = GraphData(injector, overview_iobgraph, iobCobCalculatorPlugin) val secondaryGraphsData: ArrayList<GraphData> = ArrayList()
var useIobForScale = false for (g in 0 until secondaryGraphs.size) {
var useCobForScale = false val secondGraphData = GraphData(injector, secondaryGraphs[g], iobCobCalculatorPlugin)
var useDevForScale = false var useIobForScale = false
var useRatioForScale = false var useCobForScale = false
var useDSForScale = false var useDevForScale = false
var useIAForScale = false var useRatioForScale = false
// finally enforce drawing of graphs var useDSForScale = false
when { var useIAForScale = false
sp.getBoolean("showiob", true) -> when {
useIobForScale = true overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
sp.getBoolean("showcob", true) -> overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
useCobForScale = true overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
sp.getBoolean("showdeviations", false) -> overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
useDevForScale = true overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal] -> useIAForScale = true
sp.getBoolean("showratios", false) -> overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true
useRatioForScale = true }
sp.getBoolean("showactivitysecondary", false) ->
useIAForScale = 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])
sp.getBoolean("showdevslope", false) -> if (overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, now, useCobForScale, if (useCobForScale) 1.0 else 0.5)
useDSForScale = true 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 // do GUI update
val activity = activity val activity = activity
activity?.runOnUiThread { 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 // finally enforce drawing of graphs
graphData.performUpdate() 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() }).start()
} }

View file

@ -10,8 +10,12 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.ImageButton import android.widget.ImageButton
import androidx.annotation.ColorRes
import androidx.annotation.StringRes
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.fragment.app.FragmentManager 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.Config
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.ErrorHelperActivity 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.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import java.lang.reflect.Type
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -57,131 +62,95 @@ class OverviewMenus @Inject constructor(
private val loopPlugin: LoopPlugin private val loopPlugin: LoopPlugin
) { ) {
enum class CharType { enum class CharType(@StringRes val nameId: Int, @ColorRes val colorId: Int, val primary: Boolean, val secondary: Boolean) {
PRE, BAS, IOB, COB, DEV, SEN, ACTPRIM, ACTSEC, DEVSLOPE 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<Array<Boolean>> = 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<Array<Boolean>>::class.java).toMutableList()
else {
setting = ArrayList()
setting.add(Array(CharType.values().size) { true })
}
} }
fun setupChartMenu(chartButton: ImageButton) { fun setupChartMenu(chartButton: ImageButton) {
loadGraphConfig()
val numOfGraphs = setting.size // 1 main + x secondary
chartButton.setOnClickListener { v: View -> chartButton.setOnClickListener { v: View ->
val predictionsAvailable: Boolean = when { val predictionsAvailable: Boolean = when {
Config.APS -> loopPlugin.lastRun?.request?.hasPredictions ?: false Config.APS -> loopPlugin.lastRun?.request?.hasPredictions ?: false
Config.NSCLIENT -> true Config.NSCLIENT -> true
else -> false else -> false
} }
//var item: MenuItem
val dividerItem: MenuItem
//var title: CharSequence
var titleMaxChars = 0
//var s: SpannableString
val popup = PopupMenu(v.context, v) val popup = PopupMenu(v.context, v)
if (predictionsAvailable) {
val item = popup.menu.add(Menu.NONE, CharType.PRE.ordinal, Menu.NONE, "Predictions") for (g in 0 until numOfGraphs) {
val title = item.title if (g != 0 && g < numOfGraphs) {
if (titleMaxChars < title.length) titleMaxChars = title.length val dividerItem = popup.menu.add(Menu.NONE, g, Menu.NONE, "------- " + "Graph" + " " + g + " -------")
val s = SpannableString(title) dividerItem.isCheckable = true
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.prediction)), 0, s.length, 0) dividerItem.isChecked = true
item.title = s }
item.isCheckable = true CharType.values().forEach { m ->
item.isChecked = sp.getBoolean("showprediction", true) 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 { if (numOfGraphs < MAX_GRAPHS) {
val item = popup.menu.add(Menu.NONE, CharType.BAS.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_basals)) val dividerItem = popup.menu.add(Menu.NONE, numOfGraphs, Menu.NONE, "------- " + "Graph" + " " + numOfGraphs + " -------")
val title = item.title dividerItem.isCheckable = true
if (titleMaxChars < title.length) titleMaxChars = title.length dividerItem.isChecked = false
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)
} }
// Fairly good estimate for required divider text size...
dividerItem.title = String(CharArray(titleMaxChars + 10)).replace("\u0000", "_")
popup.setOnMenuItemClickListener { popup.setOnMenuItemClickListener {
when (it.itemId) { // id < 100 graph header - divider 1, 2, 3 .....
CharType.PRE.ordinal -> sp.putBoolean("showprediction", !it.isChecked) if (it.itemId == numOfGraphs) {
CharType.BAS.ordinal -> sp.putBoolean("showbasals", !it.isChecked) // add new empty
CharType.IOB.ordinal -> sp.putBoolean("showiob", !it.isChecked) setting.add(Array(CharType.values().size) { false })
CharType.COB.ordinal -> sp.putBoolean("showcob", !it.isChecked) } else if (it.itemId < 100) {
CharType.DEV.ordinal -> sp.putBoolean("showdeviations", !it.isChecked) // remove graph
CharType.SEN.ordinal -> sp.putBoolean("showratios", !it.isChecked) setting.removeAt(it.itemId)
CharType.ACTPRIM.ordinal -> sp.putBoolean("showactivityprimary", !it.isChecked) } else {
CharType.ACTSEC.ordinal -> sp.putBoolean("showactivitysecondary", !it.isChecked) val graphNumber = it.itemId / 100 - 1
CharType.DEVSLOPE.ordinal -> sp.putBoolean("showdevslope", !it.isChecked) 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 return@setOnMenuItemClickListener true
} }
chartButton.setImageResource(R.drawable.ic_arrow_drop_up_white_24dp) chartButton.setImageResource(R.drawable.ic_arrow_drop_up_white_24dp)

View file

@ -11,7 +11,7 @@ import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin 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.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning
import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress

View file

@ -25,6 +25,6 @@ class InsulinFragment : DaggerFragment() {
insulin_name?.setText(activePlugin.getActiveInsulin().getFriendlyName()) insulin_name?.setText(activePlugin.getActiveInsulin().getFriendlyName())
insulin_comment?.setText(activePlugin.getActiveInsulin().getComment()) insulin_comment?.setText(activePlugin.getActiveInsulin().getComment())
insulin_dia?.text = resourceHelper.gs(R.string.dia) + ": " + activePlugin.getActiveInsulin().getDia() + "h" insulin_dia?.text = resourceHelper.gs(R.string.dia) + ": " + activePlugin.getActiveInsulin().getDia() + "h"
insuling_graph?.show(activePlugin.getActiveInsulin()) insulin_graph?.show(activePlugin.getActiveInsulin())
} }
} }

View file

@ -644,7 +644,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
} finally { } finally {
pump.activity = null; pump.activity = null;
rxBus.send(new EventComboPumpUpdateGUI()); rxBus.send(new EventComboPumpUpdateGUI());
rxBus.send(new EventRefreshOverview("Bolus")); rxBus.send(new EventRefreshOverview("Bolus", false));
cancelBolus = false; cancelBolus = false;
} }
} }

View file

@ -464,7 +464,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
lastUpdated = System.currentTimeMillis(); lastUpdated = System.currentTimeMillis();
new Handler(Looper.getMainLooper()).post(() -> { new Handler(Looper.getMainLooper()).post(() -> {
rxBus.send(new EventLocalInsightUpdateGUI()); 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) { } catch (Exception e) {
aapsLogger.error("Exception while reading history", 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<HistoryEvent> historyEvents) { private void processHistoryEvents(String serial, List<HistoryEvent> historyEvents) {
@ -1662,7 +1662,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
activeTBR = null; activeTBR = null;
activeBoluses = null; activeBoluses = null;
tbrOverNotificationBlock = 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())); new Handler(Looper.getMainLooper()).post(() -> rxBus.send(new EventLocalInsightUpdateGUI()));
} }

View file

@ -1073,7 +1073,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
private void finishAction(String overviewKey) { private void finishAction(String overviewKey) {
if (overviewKey != null) if (overviewKey != null)
rxBus.send(new EventRefreshOverview(overviewKey)); rxBus.send(new EventRefreshOverview(overviewKey, false));
triggerUIChange(); triggerUIChange();

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.utils package info.nightscout.androidaps.utils
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.utils.extensions.toHex import info.nightscout.androidaps.utils.extensions.toHex
import org.spongycastle.util.encoders.Base64 import org.spongycastle.util.encoders.Base64
import java.nio.ByteBuffer import java.nio.ByteBuffer
@ -13,16 +14,24 @@ import javax.crypto.SecretKeyFactory
import javax.crypto.spec.GCMParameterSpec import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.PBEKeySpec import javax.crypto.spec.PBEKeySpec
import javax.crypto.spec.SecretKeySpec 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 companion object {
private const val TAG_LENGTH_BIT = 128 private const val IV_LENGTH_BYTE = 12
private const val AES_KEY_SIZE_BIT = 256 private const val TAG_LENGTH_BIT = 128
private const val PBKDF2_ITERATIONS = 50000 // check delays it cause on real device private const val AES_KEY_SIZE_BIT = 256
private const val SALT_SIZE_BYTE = 32 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() private val secureRandom: SecureRandom = SecureRandom()
var lastException: Exception? = null
fun sha256(source: String): String { fun sha256(source: String): String {
val digest = MessageDigest.getInstance("SHA-256") val digest = MessageDigest.getInstance("SHA-256")
@ -31,29 +40,30 @@ object CryptoUtil {
} }
fun hmac256(str: String, secret: String): String? { fun hmac256(str: String, secret: String): String? {
val sha256_HMAC = Mac.getInstance("HmacSHA256") val sha256HMAC = Mac.getInstance("HmacSHA256")
val secretKey = SecretKeySpec(secret.toByteArray(), "HmacSHA256") val secretKey = SecretKeySpec(secret.toByteArray(), "HmacSHA256")
sha256_HMAC.init(secretKey) sha256HMAC.init(secretKey)
return sha256_HMAC.doFinal(str.toByteArray()).toHex() 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 factory: SecretKeyFactory = SecretKeyFactory.getInstance("PBKDF2withHmacSHA1")
val spec: KeySpec = PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount, keyStrength) val spec: KeySpec = PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount, keyStrength)
val tmp: SecretKey = factory.generateSecret(spec) 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) val salt = ByteArray(len)
secureRandom.nextBytes(salt) secureRandom.nextBytes(salt)
return 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 iv: ByteArray?
val encrypted: ByteArray? val encrypted: ByteArray?
return try { return try {
lastException = null
iv = ByteArray(IV_LENGTH_BYTE) iv = ByteArray(IV_LENGTH_BYTE)
secureRandom.nextBytes(iv) secureRandom.nextBytes(iv)
val cipherEnc: Cipher = Cipher.getInstance("AES/GCM/NoPadding") val cipherEnc: Cipher = Cipher.getInstance("AES/GCM/NoPadding")
@ -65,14 +75,17 @@ object CryptoUtil {
byteBuffer.put(encrypted) byteBuffer.put(encrypted)
String(Base64.encode(byteBuffer.array())) String(Base64.encode(byteBuffer.array()))
} catch (e: Exception) { } 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 iv: ByteArray?
val encrypted: ByteArray? val encrypted: ByteArray?
return try { return try {
lastException = null
val byteBuffer = ByteBuffer.wrap(Base64.decode(encryptedData)) val byteBuffer = ByteBuffer.wrap(Base64.decode(encryptedData))
val ivLength = byteBuffer.get().toInt() val ivLength = byteBuffer.get().toInt()
iv = ByteArray(ivLength) iv = ByteArray(ivLength)
@ -84,6 +97,8 @@ object CryptoUtil {
val dec = cipherDec.doFinal(encrypted) val dec = cipherDec.doFinal(encrypted)
String(dec) String(dec)
} catch (e: Exception) { } catch (e: Exception) {
lastException = e
aapsLogger.error("Decryption failed due to technical exception: $e")
null null
} }
} }

View file

@ -19,7 +19,10 @@ import javax.inject.Singleton
val AUTOFILL_HINT_NEW_PASSWORD = "newPassword" val AUTOFILL_HINT_NEW_PASSWORD = "newPassword"
@Singleton @Singleton
class PasswordCheck @Inject constructor(val sp: SP) { class PasswordCheck @Inject constructor(
val sp: SP,
val cryptoUtil: CryptoUtil
) {
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
fun queryPassword(context: Context, @StringRes labelId: Int, @StringRes preference: Int, ok: ( (String) -> Unit)?, cancel: (()->Unit)? = null, fail: (()->Unit)? = null) { 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)) .setCustomTitle(AlertDialogHelper.buildCustomTitle(context, context.getString(labelId), R.drawable.ic_header_key))
.setPositiveButton(context.getString(R.string.ok)) { _, _ -> .setPositiveButton(context.getString(R.string.ok)) { _, _ ->
val enteredPassword = userInput.text.toString() val enteredPassword = userInput.text.toString()
if (CryptoUtil.checkPassword(enteredPassword, password)) ok?.invoke(enteredPassword) if (cryptoUtil.checkPassword(enteredPassword, password)) ok?.invoke(enteredPassword)
else { else {
ToastUtils.errorToast(context, context.getString(R.string.wrongpassword)) ToastUtils.errorToast(context, context.getString(R.string.wrongpassword))
fail?.invoke() fail?.invoke()
@ -80,7 +83,7 @@ class PasswordCheck @Inject constructor(val sp: SP) {
.setPositiveButton(context.getString(R.string.ok)) { _, _ -> .setPositiveButton(context.getString(R.string.ok)) { _, _ ->
val enteredPassword = userInput.text.toString() val enteredPassword = userInput.text.toString()
if (enteredPassword.isNotEmpty()) { if (enteredPassword.isNotEmpty()) {
sp.putString(preference, CryptoUtil.hashPassword(enteredPassword)) sp.putString(preference, cryptoUtil.hashPassword(enteredPassword))
ToastUtils.okToast(context, context.getString(R.string.password_set)) ToastUtils.okToast(context, context.getString(R.string.password_set))
ok?.invoke(enteredPassword) ok?.invoke(enteredPassword)
} else { } else {

View file

@ -35,7 +35,7 @@
android:textAppearance="?android:attr/textAppearanceMedium" /> android:textAppearance="?android:attr/textAppearanceMedium" />
<info.nightscout.androidaps.plugins.insulin.ActivityGraph <info.nightscout.androidaps.plugins.insulin.ActivityGraph
android:id="@+id/insuling_graph" android:id="@+id/insulin_graph"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_margin="20dp" android:layout_margin="20dp"
android:layout_height="200dip" /> android:layout_height="200dip" />

View file

@ -452,10 +452,11 @@
app:layout_constraintTop_toTopOf="@+id/overview_bggraph" /> app:layout_constraintTop_toTopOf="@+id/overview_bggraph" />
<com.jjoe64.graphview.GraphView <LinearLayout
android:id="@+id/overview_iobgraph" android:id="@+id/overview_iobgraph"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="100dp" android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"

View file

@ -452,10 +452,11 @@
app:layout_constraintTop_toTopOf="@+id/overview_bggraph" /> app:layout_constraintTop_toTopOf="@+id/overview_bggraph" />
<com.jjoe64.graphview.GraphView <LinearLayout
android:id="@+id/overview_iobgraph" android:id="@+id/overview_iobgraph"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="100dp" android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@+id/overview_accepttempbutton" app:layout_constraintBottom_toTopOf="@+id/overview_accepttempbutton"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"

View file

@ -534,10 +534,11 @@
app:layout_constraintTop_toTopOf="@+id/overview_bggraph" /> app:layout_constraintTop_toTopOf="@+id/overview_bggraph" />
<com.jjoe64.graphview.GraphView <LinearLayout
android:id="@+id/overview_iobgraph" android:id="@+id/overview_iobgraph"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="100dp" android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"

View file

@ -98,8 +98,8 @@
android:layout_marginLeft="5dp" android:layout_marginLeft="5dp"
android:layout_marginRight="5dp" android:layout_marginRight="5dp"
android:gravity="center_vertical|center_horizontal" android:gravity="center_vertical|center_horizontal"
android:paddingBottom="3dp"
android:paddingTop="3dp" android:paddingTop="3dp"
android:paddingBottom="3dp"
android:text="@string/initializing" android:text="@string/initializing"
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout> </LinearLayout>
@ -208,8 +208,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="0" android:layout_weight="0"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:paddingEnd="2dp"
android:paddingStart="2dp" android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":" android:text=":"
android:textSize="14sp" /> android:textSize="14sp" />
@ -230,10 +230,10 @@
<View <View
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="2dip" android:layout_height="2dip"
android:layout_marginBottom="5dp"
android:layout_marginLeft="20dp" android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="5dp" android:layout_marginTop="5dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="5dp"
android:background="@color/listdelimiter" /> android:background="@color/listdelimiter" />
@ -256,8 +256,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="0" android:layout_weight="0"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:paddingEnd="2dp"
android:paddingStart="2dp" android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":" android:text=":"
android:textSize="14sp" /> android:textSize="14sp" />
@ -278,10 +278,10 @@
<View <View
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="2dip" android:layout_height="2dip"
android:layout_marginBottom="5dp"
android:layout_marginLeft="20dp" android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="5dp" android:layout_marginTop="5dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="5dp"
android:background="@color/listdelimiter" /> android:background="@color/listdelimiter" />
@ -304,8 +304,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="0" android:layout_weight="0"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:paddingEnd="2dp"
android:paddingStart="2dp" android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":" android:text=":"
android:textSize="14sp" /> android:textSize="14sp" />
@ -326,10 +326,10 @@
<View <View
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="2dip" android:layout_height="2dip"
android:layout_marginBottom="5dp"
android:layout_marginLeft="20dp" android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="5dp" android:layout_marginTop="5dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="5dp"
android:background="@color/listdelimiter" /> android:background="@color/listdelimiter" />
<LinearLayout <LinearLayout
@ -351,8 +351,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="0" android:layout_weight="0"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:paddingEnd="2dp"
android:paddingStart="2dp" android:paddingStart="2dp"
android:paddingEnd="2dp"
android:text=":" android:text=":"
android:textSize="14sp" /> android:textSize="14sp" />
@ -373,10 +373,10 @@
<View <View
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="2dip" android:layout_height="2dip"
android:layout_marginBottom="5dp"
android:layout_marginLeft="20dp" android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="5dp" android:layout_marginTop="5dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="5dp"
android:background="@color/listdelimiter" /> android:background="@color/listdelimiter" />
</LinearLayout> </LinearLayout>
@ -425,10 +425,10 @@
<View <View
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="2dip" android:layout_height="2dip"
android:layout_marginBottom="5dp"
android:layout_marginLeft="20dp" android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="5dp" android:layout_marginTop="5dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="5dp"
android:background="@color/listdelimiter" /> android:background="@color/listdelimiter" />
@ -454,10 +454,10 @@
<View <View
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="2dip" android:layout_height="2dip"
android:layout_marginBottom="5dp"
android:layout_marginLeft="20dp" android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="5dp" android:layout_marginTop="5dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="5dp"
android:background="@color/listdelimiter" /> android:background="@color/listdelimiter" />
<LinearLayout <LinearLayout
@ -482,10 +482,10 @@
<View <View
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="2dip" android:layout_height="2dip"
android:layout_marginBottom="5dp"
android:layout_marginLeft="20dp" android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="5dp" android:layout_marginTop="5dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="5dp"
android:background="@color/listdelimiter" /> android:background="@color/listdelimiter" />
</LinearLayout> </LinearLayout>
@ -512,8 +512,8 @@
android:id="@+id/overview_chartMenuButton" android:id="@+id/overview_chartMenuButton"
android:layout_width="30dp" android:layout_width="30dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:paddingTop="5dp" android:paddingTop="5dp"
app:srcCompat="@drawable/ic_arrow_drop_down_white_24dp" /> app:srcCompat="@drawable/ic_arrow_drop_down_white_24dp" />
@ -526,10 +526,11 @@
</RelativeLayout> </RelativeLayout>
<com.jjoe64.graphview.GraphView <LinearLayout
android:id="@+id/overview_iobgraph" android:id="@+id/overview_iobgraph"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="100dp" /> android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout> </LinearLayout>

View file

@ -1813,4 +1813,7 @@
<string name="invalidpairing">Invalid pairing information. Requesting new pairing</string> <string name="invalidpairing">Invalid pairing information. Requesting new pairing</string>
<string name="onconnect">On connect</string> <string name="onconnect">On connect</string>
<string name="ondisconnect">On disconnect</string> <string name="ondisconnect">On disconnect</string>
<string name="overview_show_predictions">Predictions</string>
<string name="overview_show_deviationslope">Deviation slope</string>
<string name="key_graphconfig" translatable="false">graphconfig</string>
</resources> </resources>

View file

@ -7,7 +7,6 @@ import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin 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.aps.openAPSSMB.OpenAPSSMBPlugin
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
@ -44,7 +43,7 @@ import java.util.*
* Created by mike on 18.03.2018. * Created by mike on 18.03.2018.
*/ */
@RunWith(PowerMockRunner::class) @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() { class ConstraintsCheckerTest : TestBaseWithProfile() {
@Mock lateinit var activePlugin: ActivePluginProvider @Mock lateinit var activePlugin: ActivePluginProvider
@ -70,7 +69,6 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
private lateinit var insightPlugin: LocalInsightPlugin private lateinit var insightPlugin: LocalInsightPlugin
private lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin private lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin
private lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin private lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin
private lateinit var openAPSMAPlugin: OpenAPSMAPlugin
private lateinit var hardLimits: HardLimits private lateinit var hardLimits: HardLimits
val injector = HasAndroidInjector { val injector = HasAndroidInjector {
@ -119,8 +117,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
insightPlugin = LocalInsightPlugin(injector, aapsLogger, rxBus, resourceHelper, treatmentsPlugin, sp, commandQueue, profileFunction, context) insightPlugin = LocalInsightPlugin(injector, aapsLogger, rxBus, resourceHelper, treatmentsPlugin, sp, commandQueue, profileFunction, context)
openAPSSMBPlugin = OpenAPSSMBPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsPlugin, iobCobCalculatorPlugin, hardLimits) 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) 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, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, treatmentsPlugin)
safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, treatmentsPlugin)
val constraintsPluginsList = ArrayList<PluginBase?>() val constraintsPluginsList = ArrayList<PluginBase?>()
constraintsPluginsList.add(safetyPlugin) constraintsPluginsList.add(safetyPlugin)
constraintsPluginsList.add(objectivesPlugin) 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.getDouble(R.string.key_openapsma_max_iob, 1.5)).thenReturn(1.5)
`when`(sp.getString(R.string.key_age, "")).thenReturn("teenage") `when`(sp.getString(R.string.key_age, "")).thenReturn("teenage")
openAPSAMAPlugin.setPluginEnabled(PluginType.APS, true) openAPSAMAPlugin.setPluginEnabled(PluginType.APS, true)
openAPSMAPlugin.setPluginEnabled(PluginType.APS, false)
openAPSSMBPlugin.setPluginEnabled(PluginType.APS, false) openAPSSMBPlugin.setPluginEnabled(PluginType.APS, false)
// Apply all limits // Apply all limits
@ -333,7 +329,6 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
`when`(sp.getString(R.string.key_age, "")).thenReturn("teenage") `when`(sp.getString(R.string.key_age, "")).thenReturn("teenage")
openAPSSMBPlugin.setPluginEnabled(PluginType.APS, true) openAPSSMBPlugin.setPluginEnabled(PluginType.APS, true)
openAPSAMAPlugin.setPluginEnabled(PluginType.APS, false) openAPSAMAPlugin.setPluginEnabled(PluginType.APS, false)
openAPSMAPlugin.setPluginEnabled(PluginType.APS, false)
// Apply all limits // Apply all limits
val d = constraintChecker.getMaxIOBAllowed() val d = constraintChecker.getMaxIOBAllowed()

View file

@ -10,7 +10,6 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider
import info.nightscout.androidaps.interfaces.Constraint import info.nightscout.androidaps.interfaces.Constraint
import info.nightscout.androidaps.interfaces.PumpDescription import info.nightscout.androidaps.interfaces.PumpDescription
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin 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.aps.openAPSSMB.OpenAPSSMBPlugin
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
@ -35,7 +34,6 @@ class SafetyPluginTest : TestBaseWithProfile() {
@Mock lateinit var sp: SP @Mock lateinit var sp: SP
@Mock lateinit var constraintChecker: ConstraintChecker @Mock lateinit var constraintChecker: ConstraintChecker
@Mock lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin @Mock lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin
@Mock lateinit var openAPSMAPlugin: OpenAPSMAPlugin
@Mock lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin @Mock lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin
@Mock lateinit var sensitivityOref1Plugin: SensitivityOref1Plugin @Mock lateinit var sensitivityOref1Plugin: SensitivityOref1Plugin
@Mock lateinit var activePlugin: ActivePluginProvider @Mock lateinit var activePlugin: ActivePluginProvider
@ -75,7 +73,7 @@ class SafetyPluginTest : TestBaseWithProfile() {
`when`(activePlugin.activePump).thenReturn(virtualPumpPlugin) `when`(activePlugin.activePump).thenReturn(virtualPumpPlugin)
`when`(virtualPumpPlugin.pumpDescription).thenReturn(pumpDescription) `when`(virtualPumpPlugin.pumpDescription).thenReturn(pumpDescription)
hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context) 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() { @Test fun pumpDescriptionShouldLimitLoopInvocation() {

View file

@ -5,10 +5,11 @@ import info.nightscout.androidaps.TestBase
import info.nightscout.androidaps.plugins.general.maintenance.formats.* import info.nightscout.androidaps.plugins.general.maintenance.formats.*
import info.nightscout.androidaps.testing.mockers.AAPSMocker import info.nightscout.androidaps.testing.mockers.AAPSMocker
import info.nightscout.androidaps.testing.utils.SingleStringStorage 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.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers
import org.json.JSONException
import org.junit.Assert import org.junit.Assert
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -30,6 +31,8 @@ class EncryptedPrefsFormatTest : TestBase() {
@Mock lateinit var resourceHelper: ResourceHelper @Mock lateinit var resourceHelper: ResourceHelper
@Mock lateinit var sp: SP @Mock lateinit var sp: SP
var cryptoUtil: CryptoUtil = CryptoUtil(aapsLogger)
@Before @Before
fun mock() { fun mock() {
AAPSMocker.prepareMock() AAPSMocker.prepareMock()
@ -52,9 +55,11 @@ class EncryptedPrefsFormatTest : TestBase() {
"}" "}"
val storage = SingleStringStorage(frozenPrefs) val storage = SingleStringStorage(frozenPrefs)
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret")
assumeAES256isSupported(cryptoUtil)
Assert.assertThat(prefs.values.size, CoreMatchers.`is`(2)) Assert.assertThat(prefs.values.size, CoreMatchers.`is`(2))
Assert.assertThat(prefs.values["key1"], CoreMatchers.`is`("A")) Assert.assertThat(prefs.values["key1"], CoreMatchers.`is`("A"))
Assert.assertThat(prefs.values["keyB"], CoreMatchers.`is`("2")) Assert.assertThat(prefs.values["keyB"], CoreMatchers.`is`("2"))
@ -67,7 +72,7 @@ class EncryptedPrefsFormatTest : TestBase() {
@Test @Test
fun preferenceSavingTest() { fun preferenceSavingTest() {
val storage = SingleStringStorage("") val storage = SingleStringStorage("")
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
val prefs = Prefs( val prefs = Prefs(
mapOf( mapOf(
"key1" to "A", "key1" to "A",
@ -84,7 +89,7 @@ class EncryptedPrefsFormatTest : TestBase() {
@Test @Test
fun importExportStabilityTest() { fun importExportStabilityTest() {
val storage = SingleStringStorage("") val storage = SingleStringStorage("")
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
val prefsIn = Prefs( val prefsIn = Prefs(
mapOf( mapOf(
"testpref1" to "--1--", "testpref1" to "--1--",
@ -97,6 +102,8 @@ class EncryptedPrefsFormatTest : TestBase() {
encryptedFormat.savePreferences(AAPSMocker.getMockedFile(), prefsIn, "tajemnica") encryptedFormat.savePreferences(AAPSMocker.getMockedFile(), prefsIn, "tajemnica")
val prefsOut = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "tajemnica") val prefsOut = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "tajemnica")
assumeAES256isSupported(cryptoUtil)
Assert.assertThat(prefsOut.values.size, CoreMatchers.`is`(2)) Assert.assertThat(prefsOut.values.size, CoreMatchers.`is`(2))
Assert.assertThat(prefsOut.values["testpref1"], CoreMatchers.`is`("--1--")) Assert.assertThat(prefsOut.values["testpref1"], CoreMatchers.`is`("--1--"))
Assert.assertThat(prefsOut.values["testpref2"], CoreMatchers.`is`("another")) Assert.assertThat(prefsOut.values["testpref2"], CoreMatchers.`is`("another"))
@ -121,7 +128,7 @@ class EncryptedPrefsFormatTest : TestBase() {
"}" "}"
val storage = SingleStringStorage(frozenPrefs) 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") val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "it-is-NOT-right-secret")
Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0)) Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0))
@ -148,9 +155,11 @@ class EncryptedPrefsFormatTest : TestBase() {
"}" "}"
val storage = SingleStringStorage(frozenPrefs) val storage = SingleStringStorage(frozenPrefs)
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret")
assumeAES256isSupported(cryptoUtil)
// contents were not tampered and we can decrypt them // contents were not tampered and we can decrypt them
Assert.assertThat(prefs.values.size, CoreMatchers.`is`(2)) Assert.assertThat(prefs.values.size, CoreMatchers.`is`(2))
@ -173,7 +182,7 @@ class EncryptedPrefsFormatTest : TestBase() {
"}" "}"
val storage = SingleStringStorage(frozenPrefs) val storage = SingleStringStorage(frozenPrefs)
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret")
Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0)) Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0))
@ -188,7 +197,7 @@ class EncryptedPrefsFormatTest : TestBase() {
"}" "}"
val storage = SingleStringStorage(frozenPrefs) val storage = SingleStringStorage(frozenPrefs)
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret")
Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0)) Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0))
@ -200,7 +209,7 @@ class EncryptedPrefsFormatTest : TestBase() {
val frozenPrefs = "whatever man, i duno care" val frozenPrefs = "whatever man, i duno care"
val storage = SingleStringStorage(frozenPrefs) val storage = SingleStringStorage(frozenPrefs)
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret")
} }
@ -219,7 +228,7 @@ class EncryptedPrefsFormatTest : TestBase() {
"}" "}"
val storage = SingleStringStorage(frozenPrefs) val storage = SingleStringStorage(frozenPrefs)
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage) val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret") encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret")
} }

View file

@ -1,16 +1,31 @@
package info.nightscout.androidaps.utils package info.nightscout.androidaps.utils
import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.TestBase
import org.hamcrest.CoreMatchers.containsString
import org.hamcrest.CoreMatchers.not
import org.junit.Assert import org.junit.Assert
import org.junit.Assume.assumeThat
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.powermock.core.classloader.annotations.PowerMockIgnore import org.powermock.core.classloader.annotations.PowerMockIgnore
import org.powermock.modules.junit4.PowerMockRunner 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.*") @PowerMockIgnore("javax.crypto.*")
@RunWith(PowerMockRunner::class) @RunWith(PowerMockRunner::class)
class CryptoUtilTest: TestBase() { class CryptoUtilTest: TestBase() {
var cryptoUtil: CryptoUtil = CryptoUtil(aapsLogger)
@Test @Test
fun testFixedSaltCrypto() { fun testFixedSaltCrypto() {
val salt = byteArrayOf( val salt = byteArrayOf(
@ -19,30 +34,36 @@ class CryptoUtilTest: TestBase() {
val password = "thisIsFixedPassword" val password = "thisIsFixedPassword"
val payload = "FIXED-PAYLOAD" val payload = "FIXED-PAYLOAD"
val encrypted = CryptoUtil.encrypt(password, salt, payload)
val encrypted = cryptoUtil.encrypt(password, salt, payload)
assumeAES256isSupported(cryptoUtil)
Assert.assertNotNull(encrypted) Assert.assertNotNull(encrypted)
val decrypted = CryptoUtil.decrypt(password, salt, encrypted!!)
val decrypted = cryptoUtil.decrypt(password, salt, encrypted!!)
assumeAES256isSupported(cryptoUtil)
Assert.assertEquals(decrypted, payload) Assert.assertEquals(decrypted, payload)
} }
@Test @Test
fun testStandardCrypto() { fun testStandardCrypto() {
val salt = CryptoUtil.mineSalt() val salt = cryptoUtil.mineSalt()
val password = "topSikret" val password = "topSikret"
val payload = "{what:payloadYouWantToProtect}" val payload = "{what:payloadYouWantToProtect}"
val encrypted = CryptoUtil.encrypt(password, salt, payload)
val encrypted = cryptoUtil.encrypt(password, salt, payload)
assumeAES256isSupported(cryptoUtil)
Assert.assertNotNull(encrypted) Assert.assertNotNull(encrypted)
val decrypted = CryptoUtil.decrypt(password, salt, encrypted!!)
val decrypted = cryptoUtil.decrypt(password, salt, encrypted!!)
assumeAES256isSupported(cryptoUtil)
Assert.assertEquals(decrypted, payload) Assert.assertEquals(decrypted, payload)
} }
@Test @Test
fun testHashVector() { fun testHashVector() {
val payload = "{what:payloadYouWantToProtect}" val payload = "{what:payloadYouWantToProtect}"
val hash = CryptoUtil.sha256(payload) val hash = cryptoUtil.sha256(payload)
Assert.assertEquals(hash, "a1aafe3ed6cc127e6d102ddbc40a205147230e9cfd178daf108c83543bbdcd13") Assert.assertEquals(hash, "a1aafe3ed6cc127e6d102ddbc40a205147230e9cfd178daf108c83543bbdcd13")
} }
@ -51,25 +72,25 @@ class CryptoUtilTest: TestBase() {
val payload = "{what:payloadYouWantToProtect}" val payload = "{what:payloadYouWantToProtect}"
val password = "topSikret" val password = "topSikret"
val expectedHmac = "ea2213953d0f2e55047cae2d23fb4f0de1b805d55e6271efa70d6b85fb692bea" // generated using other HMAC tool val expectedHmac = "ea2213953d0f2e55047cae2d23fb4f0de1b805d55e6271efa70d6b85fb692bea" // generated using other HMAC tool
val hash = CryptoUtil.hmac256(payload, password) val hash = cryptoUtil.hmac256(payload, password)
Assert.assertEquals(hash, expectedHmac) Assert.assertEquals(hash, expectedHmac)
} }
@Test @Test
fun testPlainPasswordCheck() { fun testPlainPasswordCheck() {
Assert.assertTrue(CryptoUtil.checkPassword("same", "same")) Assert.assertTrue(cryptoUtil.checkPassword("same", "same"))
Assert.assertFalse(CryptoUtil.checkPassword("same", "other")) Assert.assertFalse(cryptoUtil.checkPassword("same", "other"))
} }
@Test @Test
fun testHashedPasswordCheck() { fun testHashedPasswordCheck() {
Assert.assertTrue(CryptoUtil.checkPassword("givenSecret", CryptoUtil.hashPassword("givenSecret"))) Assert.assertTrue(cryptoUtil.checkPassword("givenSecret", cryptoUtil.hashPassword("givenSecret")))
Assert.assertFalse(CryptoUtil.checkPassword("givenSecret", CryptoUtil.hashPassword("otherSecret"))) Assert.assertFalse(cryptoUtil.checkPassword("givenSecret", cryptoUtil.hashPassword("otherSecret")))
Assert.assertTrue(CryptoUtil.checkPassword("givenHashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1")) Assert.assertTrue(cryptoUtil.checkPassword("givenHashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
Assert.assertFalse(CryptoUtil.checkPassword("givenMashToCheck", "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:0fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
Assert.assertFalse(CryptoUtil.checkPassword("givenHashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:b0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1")) Assert.assertFalse(cryptoUtil.checkPassword("givenHashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:b0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
} }
} }