Merge remote-tracking branch 'origin/dagger3' into rs
This commit is contained in:
commit
453a55db7b
43 changed files with 333 additions and 1263 deletions
|
@ -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;
|
|
@ -19,7 +19,6 @@ import info.nightscout.androidaps.events.EventRebuildTabs
|
|||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.configBuilder.PluginStore
|
||||
|
@ -80,7 +79,6 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
|||
@Inject lateinit var medtronicPumpPlugin: MedtronicPumpPlugin
|
||||
@Inject lateinit var nsClientPlugin: NSClientPlugin
|
||||
@Inject lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin
|
||||
@Inject lateinit var openAPSMAPlugin: OpenAPSMAPlugin
|
||||
@Inject lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin
|
||||
@Inject lateinit var safetyPlugin: SafetyPlugin
|
||||
@Inject lateinit var sensitivityAAPSPlugin: SensitivityAAPSPlugin
|
||||
|
@ -162,7 +160,6 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
|||
addPreferencesFromResourceIfEnabled(glimpPlugin, rootKey)
|
||||
addPreferencesFromResourceIfEnabled(careportalPlugin, rootKey)
|
||||
addPreferencesFromResourceIfEnabled(loopPlugin, rootKey, Config.APS)
|
||||
addPreferencesFromResourceIfEnabled(openAPSMAPlugin, rootKey, Config.APS)
|
||||
addPreferencesFromResourceIfEnabled(openAPSAMAPlugin, rootKey, Config.APS)
|
||||
addPreferencesFromResourceIfEnabled(openAPSSMBPlugin, rootKey, Config.APS)
|
||||
addPreferencesFromResourceIfEnabled(sensitivityAAPSPlugin, rootKey)
|
||||
|
|
|
@ -234,7 +234,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
|||
new java.util.TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
RxBus.Companion.getINSTANCE().send(new EventRefreshOverview("resetDatabases"));
|
||||
RxBus.Companion.getINSTANCE().send(new EventRefreshOverview("resetDatabases", false));
|
||||
}
|
||||
},
|
||||
3000
|
||||
|
|
|
@ -12,8 +12,7 @@ import info.nightscout.androidaps.db.BgReading
|
|||
import info.nightscout.androidaps.db.ProfileSwitch
|
||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalResultAMA
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.DetermineBasalResultMA
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.LoggerCallback
|
||||
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB
|
||||
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.*
|
||||
|
@ -55,7 +54,6 @@ interface AppComponent : AndroidInjector<MainApp> {
|
|||
fun injectPumpEnactResult(pumpEnactResult: PumpEnactResult)
|
||||
fun injectAPSResult(apsResult: APSResult)
|
||||
fun injectDetermineBasalResultSMB(determineBasalResultSMB: DetermineBasalResultSMB)
|
||||
fun injectDetermineBasalResultMA(determineBasalResultMA: DetermineBasalResultMA)
|
||||
fun injectDetermineBasalResultAMA(determineBasalResultAMA: DetermineBasalResultAMA)
|
||||
fun injectDetermineBasalAdapterSMBJS(determineBasalAdapterSMBJS: DetermineBasalAdapterSMBJS)
|
||||
|
||||
|
|
|
@ -22,8 +22,7 @@ import info.nightscout.androidaps.logging.AAPSLogger
|
|||
import info.nightscout.androidaps.logging.AAPSLoggerProduction
|
||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.DetermineBasalResultAMA
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.DetermineBasalResultMA
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.LoggerCallback
|
||||
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB
|
||||
import info.nightscout.androidaps.plugins.configBuilder.PluginStore
|
||||
|
@ -50,6 +49,7 @@ import info.nightscout.androidaps.queue.commands.*
|
|||
import info.nightscout.androidaps.setupwizard.SWEventListener
|
||||
import info.nightscout.androidaps.setupwizard.SWScreen
|
||||
import info.nightscout.androidaps.setupwizard.elements.*
|
||||
import info.nightscout.androidaps.utils.CryptoUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelperImplementation
|
||||
|
@ -121,7 +121,6 @@ open class AppModule {
|
|||
|
||||
@ContributesAndroidInjector fun apsResultInjector(): APSResult
|
||||
@ContributesAndroidInjector fun determineBasalResultSMBInjector(): DetermineBasalResultSMB
|
||||
@ContributesAndroidInjector fun determineBasalResultMAInjector(): DetermineBasalResultMA
|
||||
@ContributesAndroidInjector fun determineBasalResultAMAInjector(): DetermineBasalResultAMA
|
||||
|
||||
@ContributesAndroidInjector
|
||||
|
@ -261,6 +260,7 @@ open class AppModule {
|
|||
|
||||
@ContributesAndroidInjector fun graphDataInjector(): GraphData
|
||||
|
||||
@ContributesAndroidInjector fun cryptoUtilInjector(): CryptoUtil
|
||||
@ContributesAndroidInjector fun importExportPrefsInjector(): ImportExportPrefs
|
||||
@ContributesAndroidInjector fun encryptedPrefsFormatInjector(): EncryptedPrefsFormat
|
||||
@ContributesAndroidInjector fun classicPrefsFormatInjector(): ClassicPrefsFormat
|
||||
|
|
|
@ -6,7 +6,6 @@ import info.nightscout.androidaps.activities.MyPreferenceFragment
|
|||
import info.nightscout.androidaps.dialogs.*
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopFragment
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAFragment
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAFragment
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBFragment
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderFragment
|
||||
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesFragment
|
||||
|
@ -64,7 +63,6 @@ abstract class FragmentsModule {
|
|||
@ContributesAndroidInjector abstract fun contributesLocalProfileFragment(): LocalProfileFragment
|
||||
@ContributesAndroidInjector abstract fun contributesObjectivesFragment(): ObjectivesFragment
|
||||
@ContributesAndroidInjector abstract fun contributesOpenAPSAMAFragment(): OpenAPSAMAFragment
|
||||
@ContributesAndroidInjector abstract fun contributesOpenAPSMAFragment(): OpenAPSMAFragment
|
||||
@ContributesAndroidInjector abstract fun contributesOpenAPSSMBFragment(): OpenAPSSMBFragment
|
||||
@ContributesAndroidInjector abstract fun contributesOverviewFragment(): OverviewFragment
|
||||
@ContributesAndroidInjector abstract fun contributesLocalInsightFragment(): LocalInsightFragment
|
||||
|
|
|
@ -11,7 +11,6 @@ import info.nightscout.androidaps.Config
|
|||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
||||
import info.nightscout.androidaps.plugins.constraints.dstHelper.DstHelperPlugin
|
||||
|
@ -188,36 +187,30 @@ abstract class PluginsModule {
|
|||
@APS
|
||||
@IntoMap
|
||||
@IntKey(210)
|
||||
abstract fun bindOpenAPSMAPlugin(plugin: OpenAPSMAPlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@APS
|
||||
@IntoMap
|
||||
@IntKey(220)
|
||||
abstract fun bindOpenAPSAMAPlugin(plugin: OpenAPSAMAPlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@APS
|
||||
@IntoMap
|
||||
@IntKey(230)
|
||||
@IntKey(220)
|
||||
abstract fun bindOpenAPSSMBPlugin(plugin: OpenAPSSMBPlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@AllConfigs
|
||||
@IntoMap
|
||||
@IntKey(240)
|
||||
@IntKey(230)
|
||||
abstract fun bindNSProfilePlugin(plugin: NSProfilePlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@NotNSClient
|
||||
@IntoMap
|
||||
@IntKey(250)
|
||||
@IntKey(240)
|
||||
abstract fun bindLocalProfilePlugin(plugin: LocalProfilePlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
@AllConfigs
|
||||
@IntoMap
|
||||
@IntKey(255)
|
||||
@IntKey(250)
|
||||
abstract fun bindAutomationPlugin(plugin: AutomationPlugin): PluginBase
|
||||
|
||||
@Binds
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
package info.nightscout.androidaps.events
|
||||
|
||||
class EventRefreshOverview(var from: String) : Event()
|
||||
class EventRefreshOverview(var from: String, val now : Boolean = false) : Event()
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.androidaps.plugins.aps.openAPSMA;
|
||||
package info.nightscout.androidaps.plugins.aps.logger;
|
||||
|
||||
import org.mozilla.javascript.ScriptableObject;
|
||||
|
|
@ -29,7 +29,7 @@ import info.nightscout.androidaps.db.TemporaryBasal;
|
|||
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||
import info.nightscout.androidaps.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.LoggerCallback;
|
||||
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;
|
||||
|
|
|
@ -9,8 +9,8 @@ import dagger.android.support.DaggerFragment
|
|||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
|
|
|
@ -23,8 +23,8 @@ import info.nightscout.androidaps.logging.AAPSLogger;
|
|||
import info.nightscout.androidaps.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui;
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui;
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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 = ""
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -29,7 +29,7 @@ import info.nightscout.androidaps.db.TemporaryBasal;
|
|||
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||
import info.nightscout.androidaps.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.LoggerCallback;
|
||||
import info.nightscout.androidaps.plugins.aps.logger.LoggerCallback;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
|
||||
|
|
|
@ -10,8 +10,8 @@ import dagger.android.support.DaggerFragment
|
|||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
|
|
|
@ -26,8 +26,8 @@ import info.nightscout.androidaps.logging.AAPSLogger;
|
|||
import info.nightscout.androidaps.logging.LTag;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.ScriptReader;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateResultGui;
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui;
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateResultGui;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;
|
||||
|
|
|
@ -20,7 +20,6 @@ import info.nightscout.androidaps.interfaces.PumpDescription;
|
|||
import info.nightscout.androidaps.interfaces.PumpInterface;
|
||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin;
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker;
|
||||
|
@ -42,7 +41,6 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
|
|||
private RxBusWrapper rxBus;
|
||||
private ConstraintChecker constraintChecker;
|
||||
private OpenAPSAMAPlugin openAPSAMAPlugin;
|
||||
private OpenAPSMAPlugin openAPSMAPlugin;
|
||||
private OpenAPSSMBPlugin openAPSSMBPlugin;
|
||||
private SensitivityOref1Plugin sensitivityOref1Plugin;
|
||||
private ActivePluginProvider activePlugin;
|
||||
|
@ -59,7 +57,6 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
|
|||
RxBusWrapper rxBus,
|
||||
ConstraintChecker constraintChecker,
|
||||
OpenAPSAMAPlugin openAPSAMAPlugin,
|
||||
OpenAPSMAPlugin openAPSMAPlugin,
|
||||
OpenAPSSMBPlugin openAPSSMBPlugin,
|
||||
SensitivityOref1Plugin sensitivityOref1Plugin,
|
||||
ActivePluginProvider activePlugin,
|
||||
|
@ -80,7 +77,6 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
|
|||
this.rxBus = rxBus;
|
||||
this.constraintChecker = constraintChecker;
|
||||
this.openAPSAMAPlugin = openAPSAMAPlugin;
|
||||
this.openAPSMAPlugin = openAPSMAPlugin;
|
||||
this.openAPSSMBPlugin = openAPSSMBPlugin;
|
||||
this.sensitivityOref1Plugin = sensitivityOref1Plugin;
|
||||
this.activePlugin = activePlugin;
|
||||
|
@ -276,8 +272,6 @@ public class SafetyPlugin extends PluginBase implements ConstraintsInterface {
|
|||
maxIobPref = sp.getDouble(R.string.key_openapsma_max_iob, 1.5d);
|
||||
maxIob.setIfSmaller(getAapsLogger(), maxIobPref, String.format(getResourceHelper().gs(R.string.limitingiob), maxIobPref, getResourceHelper().gs(R.string.maxvalueinpreferences)), this);
|
||||
|
||||
if (openAPSMAPlugin.isEnabled(PluginType.APS))
|
||||
maxIob.setIfSmaller(getAapsLogger(), hardLimits.maxIobAMA(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.maxIobAMA(), getResourceHelper().gs(R.string.hardlimit)), this);
|
||||
if (openAPSAMAPlugin.isEnabled(PluginType.APS))
|
||||
maxIob.setIfSmaller(getAapsLogger(), hardLimits.maxIobAMA(), String.format(getResourceHelper().gs(R.string.limitingiob), hardLimits.maxIobAMA(), getResourceHelper().gs(R.string.hardlimit)), this);
|
||||
if (openAPSSMBPlugin.isEnabled(PluginType.APS))
|
||||
|
|
|
@ -22,7 +22,7 @@ import info.nightscout.androidaps.interfaces.PluginType
|
|||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
||||
|
|
|
@ -18,6 +18,7 @@ import javax.inject.Singleton
|
|||
@Singleton
|
||||
class EncryptedPrefsFormat @Inject constructor(
|
||||
private var resourceHelper: ResourceHelper,
|
||||
private var cryptoUtil: CryptoUtil,
|
||||
private var storage: Storage
|
||||
) : PrefsFormat {
|
||||
|
||||
|
@ -58,14 +59,14 @@ class EncryptedPrefsFormat @Inject constructor(
|
|||
var encodedContent = ""
|
||||
|
||||
if (encrypted) {
|
||||
val salt = CryptoUtil.mineSalt()
|
||||
val salt = cryptoUtil.mineSalt()
|
||||
val rawContent = content.toString()
|
||||
val contentAttempt = CryptoUtil.encrypt(masterPassword!!, salt, rawContent)
|
||||
val contentAttempt = cryptoUtil.encrypt(masterPassword!!, salt, rawContent)
|
||||
if (contentAttempt != null) {
|
||||
encodedContent = contentAttempt
|
||||
security.put("algorithm", "v1")
|
||||
security.put("salt", salt.toHex())
|
||||
security.put("content_hash", CryptoUtil.sha256(rawContent))
|
||||
security.put("content_hash", cryptoUtil.sha256(rawContent))
|
||||
} else {
|
||||
// fallback when encryption does not work
|
||||
encrypted = false
|
||||
|
@ -80,7 +81,7 @@ class EncryptedPrefsFormat @Inject constructor(
|
|||
container.put("content", if (encrypted) encodedContent else content)
|
||||
|
||||
var fileContents = container.toString(2)
|
||||
val fileHash = CryptoUtil.hmac256(fileContents, KEY_CONSCIENCE)
|
||||
val fileHash = cryptoUtil.hmac256(fileContents, KEY_CONSCIENCE)
|
||||
|
||||
fileContents = fileContents.replace(Regex("(\\\"file_hash\\\"\\s*\\:\\s*\\\")(--to-be-calculated--)(\\\")"), "$1" + fileHash + "$3")
|
||||
|
||||
|
@ -102,7 +103,7 @@ class EncryptedPrefsFormat @Inject constructor(
|
|||
|
||||
val jsonBody = storage.getFileContents(file)
|
||||
val fileContents = jsonBody.replace(Regex("(?is)(\\\"file_hash\\\"\\s*\\:\\s*\\\")([^\"]*)(\\\")"), "$1--to-be-calculated--$3")
|
||||
val calculatedFileHash = CryptoUtil.hmac256(fileContents, KEY_CONSCIENCE)
|
||||
val calculatedFileHash = cryptoUtil.hmac256(fileContents, KEY_CONSCIENCE)
|
||||
val container = JSONObject(jsonBody)
|
||||
|
||||
if (container.has(PrefsMetadataKey.FILE_FORMAT.key) && container.has("security") && container.has("content") && container.has("metadata")) {
|
||||
|
@ -144,11 +145,11 @@ class EncryptedPrefsFormat @Inject constructor(
|
|||
if (security.has("salt") && security.has("content_hash")) {
|
||||
|
||||
val salt = security.getString("salt").hexStringToByteArray()
|
||||
val decrypted = CryptoUtil.decrypt(masterPassword!!, salt, container.getString("content"))
|
||||
val decrypted = cryptoUtil.decrypt(masterPassword!!, salt, container.getString("content"))
|
||||
|
||||
if (decrypted != null) {
|
||||
try {
|
||||
val contentHash = CryptoUtil.sha256(decrypted)
|
||||
val contentHash = cryptoUtil.sha256(decrypted)
|
||||
|
||||
if (contentHash == security.getString("content_hash")) {
|
||||
contentJsonObj = JSONObject(decrypted)
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.app.NotificationManager
|
|||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
|
@ -17,7 +18,9 @@ import android.view.MenuItem
|
|||
import android.view.View
|
||||
import android.view.View.OnLongClickListener
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.jjoe64.graphview.GraphView
|
||||
import dagger.android.HasAndroidInjector
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.Config
|
||||
|
@ -93,6 +96,7 @@ import java.util.concurrent.Executors
|
|||
import java.util.concurrent.ScheduledFuture
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.max
|
||||
|
@ -130,6 +134,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
private var smallWidth = false
|
||||
private var smallHeight = false
|
||||
private lateinit var dm: DisplayMetrics
|
||||
private var axisWidth: Int = 0
|
||||
private var rangeToDisplay = 6 // for graph
|
||||
private var loopHandler = Handler()
|
||||
private var refreshLoop: Runnable? = null
|
||||
|
@ -137,6 +142,8 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
private val worker = Executors.newSingleThreadScheduledExecutor()
|
||||
private var scheduledUpdate: ScheduledFuture<*>? = null
|
||||
|
||||
private val secondaryGraphs = ArrayList<GraphView>()
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View? {
|
||||
|
||||
|
@ -173,15 +180,11 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
|
||||
overview_notifications?.setHasFixedSize(false)
|
||||
overview_notifications?.layoutManager = LinearLayoutManager(view.context)
|
||||
val axisWidth = if (dm.densityDpi <= 120) 3 else if (dm.densityDpi <= 160) 10 else if (dm.densityDpi <= 320) 35 else if (dm.densityDpi <= 420) 50 else if (dm.densityDpi <= 560) 70 else 80
|
||||
axisWidth = if (dm.densityDpi <= 120) 3 else if (dm.densityDpi <= 160) 10 else if (dm.densityDpi <= 320) 35 else if (dm.densityDpi <= 420) 50 else if (dm.densityDpi <= 560) 70 else 80
|
||||
overview_bggraph?.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid)
|
||||
overview_bggraph?.gridLabelRenderer?.reloadStyles()
|
||||
overview_iobgraph?.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid)
|
||||
overview_iobgraph?.gridLabelRenderer?.reloadStyles()
|
||||
overview_iobgraph?.gridLabelRenderer?.isHorizontalLabelsVisible = false
|
||||
overview_bggraph?.gridLabelRenderer?.labelVerticalWidth = axisWidth
|
||||
overview_iobgraph?.gridLabelRenderer?.labelVerticalWidth = axisWidth
|
||||
overview_iobgraph?.gridLabelRenderer?.numVerticalLabels = 3
|
||||
|
||||
rangeToDisplay = sp.getInt(R.string.key_rangetodisplay, 6)
|
||||
|
||||
overview_bggraph?.setOnLongClickListener {
|
||||
|
@ -193,6 +196,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
false
|
||||
}
|
||||
overviewMenus.setupChartMenu(overview_chartMenuButton)
|
||||
prepareGraphs()
|
||||
|
||||
overview_accepttempbutton?.setOnClickListener(this)
|
||||
overview_treatmentbutton?.setOnClickListener(this)
|
||||
|
@ -218,8 +222,12 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
super.onResume()
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventRefreshOverview::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ scheduleUpdateGUI(it.from) }) { fabricPrivacy.logException(it) })
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
prepareGraphs()
|
||||
if (it.now) updateGUI(it.from)
|
||||
else scheduleUpdateGUI(it.from)
|
||||
}) { fabricPrivacy.logException(it) })
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventExtendedBolusChange::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
|
@ -464,6 +472,30 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
|
||||
}
|
||||
|
||||
private fun prepareGraphs() {
|
||||
val numOfGraphs = overviewMenus.setting.size
|
||||
|
||||
if (numOfGraphs != secondaryGraphs.size - 1) {
|
||||
//aapsLogger.debug("New secondary graph count ${numOfGraphs-1}")
|
||||
// rebuild needed
|
||||
secondaryGraphs.clear()
|
||||
overview_iobgraph.removeAllViews()
|
||||
for (i in 1 until numOfGraphs) {
|
||||
val graph = GraphView(context)
|
||||
graph.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, resourceHelper.dpToPx(100)).also { it.setMargins(0, 0, 0, resourceHelper.dpToPx(10)) }
|
||||
graph.gridLabelRenderer?.gridColor = resourceHelper.gc(R.color.graphgrid)
|
||||
graph.gridLabelRenderer?.reloadStyles()
|
||||
graph.gridLabelRenderer?.isHorizontalLabelsVisible = false
|
||||
graph.gridLabelRenderer?.labelVerticalWidth = axisWidth
|
||||
graph.gridLabelRenderer?.numVerticalLabels = 3
|
||||
graph.viewport.backgroundColor = Color.argb(20, 255, 255, 255) // 8% of gray
|
||||
overview_iobgraph.addView(graph)
|
||||
secondaryGraphs.add(graph)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun scheduleUpdateGUI(from: String) {
|
||||
class UpdateRunnable : Runnable {
|
||||
override fun run() {
|
||||
|
@ -746,19 +778,20 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
graphData.addInRangeArea(fromTime, endTime, lowLine, highLine)
|
||||
|
||||
// **** BG ****
|
||||
if (predictionsAvailable && sp.getBoolean("showprediction", false)) graphData.addBgReadings(fromTime, toTime, lowLine, highLine,
|
||||
apsResult?.predictions) else graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null)
|
||||
if (predictionsAvailable && overviewMenus.setting[0][OverviewMenus.CharType.PRE.ordinal])
|
||||
graphData.addBgReadings(fromTime, toTime, lowLine, highLine, apsResult?.predictions)
|
||||
else graphData.addBgReadings(fromTime, toTime, lowLine, highLine, null)
|
||||
|
||||
// set manual x bounds to have nice steps
|
||||
graphData.formatAxis(fromTime, endTime)
|
||||
|
||||
// Treatments
|
||||
graphData.addTreatments(fromTime, endTime)
|
||||
if (sp.getBoolean("showactivityprimary", true))
|
||||
if (overviewMenus.setting[0][OverviewMenus.CharType.ACT.ordinal])
|
||||
graphData.addActivity(fromTime, endTime, false, 0.8)
|
||||
|
||||
// add basal data
|
||||
if (pump.pumpDescription.isTempBasalCapable && sp.getBoolean("showbasals", true))
|
||||
if (pump.pumpDescription.isTempBasalCapable && overviewMenus.setting[0][OverviewMenus.CharType.BAS.ordinal])
|
||||
graphData.addBasals(fromTime, now, lowLine / graphData.maxY / 1.2)
|
||||
|
||||
// add target line
|
||||
|
@ -768,57 +801,53 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
graphData.addNowLine(now)
|
||||
|
||||
// ------------------ 2nd graph
|
||||
val secondGraphData = GraphData(injector, overview_iobgraph, iobCobCalculatorPlugin)
|
||||
val secondaryGraphsData: ArrayList<GraphData> = ArrayList()
|
||||
for (g in 0 until secondaryGraphs.size) {
|
||||
val secondGraphData = GraphData(injector, secondaryGraphs[g], iobCobCalculatorPlugin)
|
||||
var useIobForScale = false
|
||||
var useCobForScale = false
|
||||
var useDevForScale = false
|
||||
var useRatioForScale = false
|
||||
var useDSForScale = false
|
||||
var useIAForScale = false
|
||||
// finally enforce drawing of graphs
|
||||
when {
|
||||
sp.getBoolean("showiob", true) ->
|
||||
useIobForScale = true
|
||||
sp.getBoolean("showcob", true) ->
|
||||
useCobForScale = true
|
||||
sp.getBoolean("showdeviations", false) ->
|
||||
useDevForScale = true
|
||||
sp.getBoolean("showratios", false) ->
|
||||
useRatioForScale = true
|
||||
sp.getBoolean("showactivitysecondary", false) ->
|
||||
useIAForScale = true
|
||||
sp.getBoolean("showdevslope", false) ->
|
||||
useDSForScale = true
|
||||
overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
|
||||
overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal] -> useCobForScale = true
|
||||
overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal] -> useDevForScale = true
|
||||
overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
|
||||
overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal] -> useIAForScale = true
|
||||
overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true
|
||||
}
|
||||
|
||||
if (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)
|
||||
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal]) secondGraphData.addIob(fromTime, now, useIobForScale, 1.0, overviewMenus.setting[g + 1][OverviewMenus.CharType.PRE.ordinal])
|
||||
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal]) secondGraphData.addCob(fromTime, now, useCobForScale, if (useCobForScale) 1.0 else 0.5)
|
||||
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal]) secondGraphData.addDeviations(fromTime, now, useDevForScale, 1.0)
|
||||
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(fromTime, now, useRatioForScale, 1.0)
|
||||
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal]) secondGraphData.addActivity(fromTime, endTime, useIAForScale, 0.8)
|
||||
if (overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && buildHelper.isDev()) secondGraphData.addDeviationSlope(fromTime, now, useDSForScale, 1.0)
|
||||
|
||||
// **** NOW line ****
|
||||
// set manual x bounds to have nice steps
|
||||
secondGraphData.formatAxis(fromTime, endTime)
|
||||
secondGraphData.addNowLine(now)
|
||||
secondaryGraphsData.add(secondGraphData)
|
||||
}
|
||||
|
||||
// do GUI update
|
||||
val activity = activity
|
||||
activity?.runOnUiThread {
|
||||
if (sp.getBoolean("showiob", true)
|
||||
|| sp.getBoolean("showcob", true)
|
||||
|| sp.getBoolean("showdeviations", false)
|
||||
|| sp.getBoolean("showratios", false)
|
||||
|| sp.getBoolean("showactivitysecondary", false)
|
||||
|| sp.getBoolean("showdevslope", false)) {
|
||||
overview_iobgraph?.visibility = View.VISIBLE
|
||||
} else {
|
||||
overview_iobgraph?.visibility = View.GONE
|
||||
}
|
||||
// finally enforce drawing of graphs
|
||||
graphData.performUpdate()
|
||||
secondGraphData.performUpdate()
|
||||
for (g in 0 until secondaryGraphs.size) {
|
||||
secondaryGraphs[g].visibility = (
|
||||
overviewMenus.setting[g + 1][OverviewMenus.CharType.IOB.ordinal] ||
|
||||
overviewMenus.setting[g + 1][OverviewMenus.CharType.COB.ordinal] ||
|
||||
overviewMenus.setting[g + 1][OverviewMenus.CharType.DEV.ordinal] ||
|
||||
overviewMenus.setting[g + 1][OverviewMenus.CharType.SEN.ordinal] ||
|
||||
overviewMenus.setting[g + 1][OverviewMenus.CharType.ACT.ordinal] ||
|
||||
overviewMenus.setting[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal]
|
||||
).toVisibility()
|
||||
secondaryGraphsData[g].performUpdate()
|
||||
}
|
||||
}
|
||||
}).start()
|
||||
}
|
||||
|
|
|
@ -10,8 +10,12 @@ import android.view.Menu
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.ImageButton
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import info.nightscout.androidaps.Config
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.ErrorHelperActivity
|
||||
|
@ -38,6 +42,7 @@ import info.nightscout.androidaps.utils.ToastUtils
|
|||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import java.lang.reflect.Type
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -57,131 +62,95 @@ class OverviewMenus @Inject constructor(
|
|||
private val loopPlugin: LoopPlugin
|
||||
) {
|
||||
|
||||
enum class CharType {
|
||||
PRE, BAS, IOB, COB, DEV, SEN, ACTPRIM, ACTSEC, DEVSLOPE
|
||||
enum class CharType(@StringRes val nameId: Int, @ColorRes val colorId: Int, val primary: Boolean, val secondary: Boolean) {
|
||||
PRE(R.string.overview_show_predictions, R.color.prediction, primary = true, secondary = false),
|
||||
BAS(R.string.overview_show_basals, R.color.basal, primary = true, secondary = false),
|
||||
IOB(R.string.overview_show_iob, R.color.iob, primary = false, secondary = true),
|
||||
COB(R.string.overview_show_cob, R.color.cob, primary = false, secondary = true),
|
||||
DEV(R.string.overview_show_deviations, R.color.deviations, primary = false, secondary = true),
|
||||
SEN(R.string.overview_show_sensitivity, R.color.ratio, primary = false, secondary = true),
|
||||
ACT(R.string.overview_show_activity, R.color.activity, primary = true, secondary = true),
|
||||
DEVSLOPE(R.string.overview_show_deviationslope, R.color.devslopepos, primary = false, secondary = true)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val MAX_GRAPHS = 5 // including main
|
||||
}
|
||||
var setting: MutableList<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) {
|
||||
loadGraphConfig()
|
||||
val numOfGraphs = setting.size // 1 main + x secondary
|
||||
|
||||
chartButton.setOnClickListener { v: View ->
|
||||
val predictionsAvailable: Boolean = when {
|
||||
Config.APS -> loopPlugin.lastRun?.request?.hasPredictions ?: false
|
||||
Config.NSCLIENT -> true
|
||||
else -> false
|
||||
}
|
||||
//var item: MenuItem
|
||||
val dividerItem: MenuItem
|
||||
//var title: CharSequence
|
||||
var titleMaxChars = 0
|
||||
//var s: SpannableString
|
||||
val popup = PopupMenu(v.context, v)
|
||||
if (predictionsAvailable) {
|
||||
val item = popup.menu.add(Menu.NONE, CharType.PRE.ordinal, Menu.NONE, "Predictions")
|
||||
val title = item.title
|
||||
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||
val s = SpannableString(title)
|
||||
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.prediction)), 0, s.length, 0)
|
||||
item.title = s
|
||||
item.isCheckable = true
|
||||
item.isChecked = sp.getBoolean("showprediction", true)
|
||||
|
||||
for (g in 0 until numOfGraphs) {
|
||||
if (g != 0 && g < numOfGraphs) {
|
||||
val dividerItem = popup.menu.add(Menu.NONE, g, Menu.NONE, "------- " + "Graph" + " " + g + " -------")
|
||||
dividerItem.isCheckable = true
|
||||
dividerItem.isChecked = true
|
||||
}
|
||||
run {
|
||||
val item = popup.menu.add(Menu.NONE, CharType.BAS.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_basals))
|
||||
CharType.values().forEach { m ->
|
||||
if (g == 0 && !m.primary) return@forEach
|
||||
if (g > 0 && !m.secondary) return@forEach
|
||||
var insert = true
|
||||
if (m == CharType.PRE) insert = predictionsAvailable
|
||||
if (m == CharType.DEVSLOPE) insert = buildHelper.isDev()
|
||||
if (insert) {
|
||||
val item = popup.menu.add(Menu.NONE, m.ordinal + 100 * (g + 1), Menu.NONE, resourceHelper.gs(m.nameId))
|
||||
val title = item.title
|
||||
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||
val s = SpannableString(title)
|
||||
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.basal)), 0, s.length, 0)
|
||||
s.setSpan(ForegroundColorSpan(resourceHelper.gc(m.colorId)), 0, s.length, 0)
|
||||
item.title = s
|
||||
item.isCheckable = true
|
||||
item.isChecked = sp.getBoolean("showbasals", true)
|
||||
item.isChecked = setting[g][m.ordinal]
|
||||
}
|
||||
run {
|
||||
val item = popup.menu.add(Menu.NONE, CharType.ACTPRIM.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_activity))
|
||||
val title = item.title
|
||||
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||
val s = SpannableString(title)
|
||||
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.activity)), 0, s.length, 0)
|
||||
item.title = s
|
||||
item.isCheckable = true
|
||||
item.isChecked = sp.getBoolean("showactivityprimary", true)
|
||||
dividerItem = popup.menu.add("")
|
||||
dividerItem.isEnabled = false
|
||||
}
|
||||
run {
|
||||
val item = popup.menu.add(Menu.NONE, CharType.IOB.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_iob))
|
||||
val title = item.title
|
||||
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||
val s = SpannableString(title)
|
||||
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.iob)), 0, s.length, 0)
|
||||
item.title = s
|
||||
item.isCheckable = true
|
||||
item.isChecked = sp.getBoolean("showiob", true)
|
||||
}
|
||||
run {
|
||||
val item = popup.menu.add(Menu.NONE, CharType.COB.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_cob))
|
||||
val title = item.title
|
||||
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||
val s = SpannableString(title)
|
||||
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.cob)), 0, s.length, 0)
|
||||
item.title = s
|
||||
item.isCheckable = true
|
||||
item.isChecked = sp.getBoolean("showcob", true)
|
||||
}
|
||||
run {
|
||||
val item = popup.menu.add(Menu.NONE, CharType.DEV.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_deviations))
|
||||
val title = item.title
|
||||
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||
val s = SpannableString(title)
|
||||
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.deviations)), 0, s.length, 0)
|
||||
item.title = s
|
||||
item.isCheckable = true
|
||||
item.isChecked = sp.getBoolean("showdeviations", false)
|
||||
}
|
||||
run {
|
||||
val item = popup.menu.add(Menu.NONE, CharType.SEN.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_sensitivity))
|
||||
val title = item.title
|
||||
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||
val s = SpannableString(title)
|
||||
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.ratio)), 0, s.length, 0)
|
||||
item.title = s
|
||||
item.isCheckable = true
|
||||
item.isChecked = sp.getBoolean("showratios", false)
|
||||
}
|
||||
run {
|
||||
val item = popup.menu.add(Menu.NONE, CharType.ACTSEC.ordinal, Menu.NONE, resourceHelper.gs(R.string.overview_show_activity))
|
||||
val title = item.title
|
||||
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||
val s = SpannableString(title)
|
||||
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.activity)), 0, s.length, 0)
|
||||
item.title = s
|
||||
item.isCheckable = true
|
||||
item.isChecked = sp.getBoolean("showactivitysecondary", true)
|
||||
}
|
||||
if (buildHelper.isDev()) {
|
||||
val item = popup.menu.add(Menu.NONE, CharType.DEVSLOPE.ordinal, Menu.NONE, "Deviation slope")
|
||||
val title = item.title
|
||||
if (titleMaxChars < title.length) titleMaxChars = title.length
|
||||
val s = SpannableString(title)
|
||||
s.setSpan(ForegroundColorSpan(resourceHelper.gc(R.color.devslopepos)), 0, s.length, 0)
|
||||
item.title = s
|
||||
item.isCheckable = true
|
||||
item.isChecked = sp.getBoolean("showdevslope", false)
|
||||
if (numOfGraphs < MAX_GRAPHS) {
|
||||
val dividerItem = popup.menu.add(Menu.NONE, numOfGraphs, Menu.NONE, "------- " + "Graph" + " " + numOfGraphs + " -------")
|
||||
dividerItem.isCheckable = true
|
||||
dividerItem.isChecked = false
|
||||
}
|
||||
|
||||
// Fairly good estimate for required divider text size...
|
||||
dividerItem.title = String(CharArray(titleMaxChars + 10)).replace("\u0000", "_")
|
||||
popup.setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
CharType.PRE.ordinal -> sp.putBoolean("showprediction", !it.isChecked)
|
||||
CharType.BAS.ordinal -> sp.putBoolean("showbasals", !it.isChecked)
|
||||
CharType.IOB.ordinal -> sp.putBoolean("showiob", !it.isChecked)
|
||||
CharType.COB.ordinal -> sp.putBoolean("showcob", !it.isChecked)
|
||||
CharType.DEV.ordinal -> sp.putBoolean("showdeviations", !it.isChecked)
|
||||
CharType.SEN.ordinal -> sp.putBoolean("showratios", !it.isChecked)
|
||||
CharType.ACTPRIM.ordinal -> sp.putBoolean("showactivityprimary", !it.isChecked)
|
||||
CharType.ACTSEC.ordinal -> sp.putBoolean("showactivitysecondary", !it.isChecked)
|
||||
CharType.DEVSLOPE.ordinal -> sp.putBoolean("showdevslope", !it.isChecked)
|
||||
// id < 100 graph header - divider 1, 2, 3 .....
|
||||
if (it.itemId == numOfGraphs) {
|
||||
// add new empty
|
||||
setting.add(Array(CharType.values().size) { false })
|
||||
} else if (it.itemId < 100) {
|
||||
// remove graph
|
||||
setting.removeAt(it.itemId)
|
||||
} else {
|
||||
val graphNumber = it.itemId / 100 - 1
|
||||
val item = it.itemId % 100
|
||||
setting[graphNumber][item] = !it.isChecked
|
||||
}
|
||||
rxBus.send(EventRefreshOverview("OnMenuItemClickListener"))
|
||||
storeGraphConfig()
|
||||
setupChartMenu(chartButton)
|
||||
rxBus.send(EventRefreshOverview("OnMenuItemClickListener", now = true))
|
||||
return@setOnMenuItemClickListener true
|
||||
}
|
||||
chartButton.setImageResource(R.drawable.ic_arrow_drop_up_white_24dp)
|
||||
|
|
|
@ -11,7 +11,7 @@ import info.nightscout.androidaps.interfaces.PluginDescription
|
|||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.events.EventOpenAPSUpdateGui
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress
|
||||
|
|
|
@ -25,6 +25,6 @@ class InsulinFragment : DaggerFragment() {
|
|||
insulin_name?.setText(activePlugin.getActiveInsulin().getFriendlyName())
|
||||
insulin_comment?.setText(activePlugin.getActiveInsulin().getComment())
|
||||
insulin_dia?.text = resourceHelper.gs(R.string.dia) + ": " + activePlugin.getActiveInsulin().getDia() + "h"
|
||||
insuling_graph?.show(activePlugin.getActiveInsulin())
|
||||
insulin_graph?.show(activePlugin.getActiveInsulin())
|
||||
}
|
||||
}
|
|
@ -644,7 +644,7 @@ public class ComboPlugin extends PumpPluginBase implements PumpInterface, Constr
|
|||
} finally {
|
||||
pump.activity = null;
|
||||
rxBus.send(new EventComboPumpUpdateGUI());
|
||||
rxBus.send(new EventRefreshOverview("Bolus"));
|
||||
rxBus.send(new EventRefreshOverview("Bolus", false));
|
||||
cancelBolus = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -464,7 +464,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
|
|||
lastUpdated = System.currentTimeMillis();
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
rxBus.send(new EventLocalInsightUpdateGUI());
|
||||
rxBus.send(new EventRefreshOverview("LocalInsightPlugin::fetchStatus"));
|
||||
rxBus.send(new EventRefreshOverview("LocalInsightPlugin::fetchStatus", false));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1215,7 +1215,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
|
|||
} catch (Exception e) {
|
||||
aapsLogger.error("Exception while reading history", e);
|
||||
}
|
||||
new Handler(Looper.getMainLooper()).post(() -> rxBus.send(new EventRefreshOverview("LocalInsightPlugin::readHistory")));
|
||||
new Handler(Looper.getMainLooper()).post(() -> rxBus.send(new EventRefreshOverview("LocalInsightPlugin::readHistory", false)));
|
||||
}
|
||||
|
||||
private void processHistoryEvents(String serial, List<HistoryEvent> historyEvents) {
|
||||
|
@ -1662,7 +1662,7 @@ public class LocalInsightPlugin extends PumpPluginBase implements PumpInterface,
|
|||
activeTBR = null;
|
||||
activeBoluses = null;
|
||||
tbrOverNotificationBlock = null;
|
||||
new Handler(Looper.getMainLooper()).post(() -> rxBus.send(new EventRefreshOverview("LocalInsightPlugin::onStateChanged")));
|
||||
new Handler(Looper.getMainLooper()).post(() -> rxBus.send(new EventRefreshOverview("LocalInsightPlugin::onStateChanged", false)));
|
||||
}
|
||||
new Handler(Looper.getMainLooper()).post(() -> rxBus.send(new EventLocalInsightUpdateGUI()));
|
||||
}
|
||||
|
|
|
@ -1073,7 +1073,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
|
|||
private void finishAction(String overviewKey) {
|
||||
|
||||
if (overviewKey != null)
|
||||
rxBus.send(new EventRefreshOverview(overviewKey));
|
||||
rxBus.send(new EventRefreshOverview(overviewKey, false));
|
||||
|
||||
triggerUIChange();
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.utils
|
||||
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.utils.extensions.toHex
|
||||
import org.spongycastle.util.encoders.Base64
|
||||
import java.nio.ByteBuffer
|
||||
|
@ -13,16 +14,24 @@ import javax.crypto.SecretKeyFactory
|
|||
import javax.crypto.spec.GCMParameterSpec
|
||||
import javax.crypto.spec.PBEKeySpec
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
object CryptoUtil {
|
||||
@Singleton
|
||||
class CryptoUtil @Inject constructor(
|
||||
val aapsLogger: AAPSLogger
|
||||
) {
|
||||
|
||||
companion object {
|
||||
private const val IV_LENGTH_BYTE = 12
|
||||
private const val TAG_LENGTH_BIT = 128
|
||||
private const val AES_KEY_SIZE_BIT = 256
|
||||
private const val PBKDF2_ITERATIONS = 50000 // check delays it cause on real device
|
||||
private const val SALT_SIZE_BYTE = 32
|
||||
}
|
||||
|
||||
private val secureRandom: SecureRandom = SecureRandom()
|
||||
var lastException: Exception? = null
|
||||
|
||||
fun sha256(source: String): String {
|
||||
val digest = MessageDigest.getInstance("SHA-256")
|
||||
|
@ -31,17 +40,17 @@ object CryptoUtil {
|
|||
}
|
||||
|
||||
fun hmac256(str: String, secret: String): String? {
|
||||
val sha256_HMAC = Mac.getInstance("HmacSHA256")
|
||||
val sha256HMAC = Mac.getInstance("HmacSHA256")
|
||||
val secretKey = SecretKeySpec(secret.toByteArray(), "HmacSHA256")
|
||||
sha256_HMAC.init(secretKey)
|
||||
return sha256_HMAC.doFinal(str.toByteArray()).toHex()
|
||||
sha256HMAC.init(secretKey)
|
||||
return sha256HMAC.doFinal(str.toByteArray()).toHex()
|
||||
}
|
||||
|
||||
private fun prepCipherKey(passPhrase: String, salt: ByteArray, iterationCount: Int = PBKDF2_ITERATIONS, keyStrength: Int = AES_KEY_SIZE_BIT): SecretKeySpec {
|
||||
val factory: SecretKeyFactory = SecretKeyFactory.getInstance("PBKDF2withHmacSHA1")
|
||||
val spec: KeySpec = PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount, keyStrength)
|
||||
val tmp: SecretKey = factory.generateSecret(spec)
|
||||
return SecretKeySpec(tmp.getEncoded(), "AES")
|
||||
return SecretKeySpec(tmp.encoded, "AES")
|
||||
}
|
||||
|
||||
fun mineSalt(len: Int = SALT_SIZE_BYTE): ByteArray {
|
||||
|
@ -54,6 +63,7 @@ object CryptoUtil {
|
|||
val iv: ByteArray?
|
||||
val encrypted: ByteArray?
|
||||
return try {
|
||||
lastException = null
|
||||
iv = ByteArray(IV_LENGTH_BYTE)
|
||||
secureRandom.nextBytes(iv)
|
||||
val cipherEnc: Cipher = Cipher.getInstance("AES/GCM/NoPadding")
|
||||
|
@ -65,6 +75,8 @@ object CryptoUtil {
|
|||
byteBuffer.put(encrypted)
|
||||
String(Base64.encode(byteBuffer.array()))
|
||||
} catch (e: Exception) {
|
||||
lastException = e
|
||||
aapsLogger.error("Encryption failed due to technical exception: $e")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +85,7 @@ object CryptoUtil {
|
|||
val iv: ByteArray?
|
||||
val encrypted: ByteArray?
|
||||
return try {
|
||||
lastException = null
|
||||
val byteBuffer = ByteBuffer.wrap(Base64.decode(encryptedData))
|
||||
val ivLength = byteBuffer.get().toInt()
|
||||
iv = ByteArray(ivLength)
|
||||
|
@ -84,6 +97,8 @@ object CryptoUtil {
|
|||
val dec = cipherDec.doFinal(encrypted)
|
||||
String(dec)
|
||||
} catch (e: Exception) {
|
||||
lastException = e
|
||||
aapsLogger.error("Decryption failed due to technical exception: $e")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,10 @@ import javax.inject.Singleton
|
|||
val AUTOFILL_HINT_NEW_PASSWORD = "newPassword"
|
||||
|
||||
@Singleton
|
||||
class PasswordCheck @Inject constructor(val sp: SP) {
|
||||
class PasswordCheck @Inject constructor(
|
||||
val sp: SP,
|
||||
val cryptoUtil: CryptoUtil
|
||||
) {
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
fun queryPassword(context: Context, @StringRes labelId: Int, @StringRes preference: Int, ok: ( (String) -> Unit)?, cancel: (()->Unit)? = null, fail: (()->Unit)? = null) {
|
||||
|
@ -45,7 +48,7 @@ class PasswordCheck @Inject constructor(val sp: SP) {
|
|||
.setCustomTitle(AlertDialogHelper.buildCustomTitle(context, context.getString(labelId), R.drawable.ic_header_key))
|
||||
.setPositiveButton(context.getString(R.string.ok)) { _, _ ->
|
||||
val enteredPassword = userInput.text.toString()
|
||||
if (CryptoUtil.checkPassword(enteredPassword, password)) ok?.invoke(enteredPassword)
|
||||
if (cryptoUtil.checkPassword(enteredPassword, password)) ok?.invoke(enteredPassword)
|
||||
else {
|
||||
ToastUtils.errorToast(context, context.getString(R.string.wrongpassword))
|
||||
fail?.invoke()
|
||||
|
@ -80,7 +83,7 @@ class PasswordCheck @Inject constructor(val sp: SP) {
|
|||
.setPositiveButton(context.getString(R.string.ok)) { _, _ ->
|
||||
val enteredPassword = userInput.text.toString()
|
||||
if (enteredPassword.isNotEmpty()) {
|
||||
sp.putString(preference, CryptoUtil.hashPassword(enteredPassword))
|
||||
sp.putString(preference, cryptoUtil.hashPassword(enteredPassword))
|
||||
ToastUtils.okToast(context, context.getString(R.string.password_set))
|
||||
ok?.invoke(enteredPassword)
|
||||
} else {
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<info.nightscout.androidaps.plugins.insulin.ActivityGraph
|
||||
android:id="@+id/insuling_graph"
|
||||
android:id="@+id/insulin_graph"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_margin="20dp"
|
||||
android:layout_height="200dip" />
|
||||
|
|
|
@ -452,10 +452,11 @@
|
|||
app:layout_constraintTop_toTopOf="@+id/overview_bggraph" />
|
||||
|
||||
|
||||
<com.jjoe64.graphview.GraphView
|
||||
<LinearLayout
|
||||
android:id="@+id/overview_iobgraph"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
|
@ -452,10 +452,11 @@
|
|||
app:layout_constraintTop_toTopOf="@+id/overview_bggraph" />
|
||||
|
||||
|
||||
<com.jjoe64.graphview.GraphView
|
||||
<LinearLayout
|
||||
android:id="@+id/overview_iobgraph"
|
||||
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_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
|
@ -534,10 +534,11 @@
|
|||
app:layout_constraintTop_toTopOf="@+id/overview_bggraph" />
|
||||
|
||||
|
||||
<com.jjoe64.graphview.GraphView
|
||||
<LinearLayout
|
||||
android:id="@+id/overview_iobgraph"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
|
@ -98,8 +98,8 @@
|
|||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:gravity="center_vertical|center_horizontal"
|
||||
android:paddingBottom="3dp"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingBottom="3dp"
|
||||
android:text="@string/initializing"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
</LinearLayout>
|
||||
|
@ -208,8 +208,8 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:gravity="center_horizontal"
|
||||
android:paddingEnd="2dp"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingEnd="2dp"
|
||||
android:text=":"
|
||||
android:textSize="14sp" />
|
||||
|
||||
|
@ -230,10 +230,10 @@
|
|||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:background="@color/listdelimiter" />
|
||||
|
||||
|
||||
|
@ -256,8 +256,8 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:gravity="center_horizontal"
|
||||
android:paddingEnd="2dp"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingEnd="2dp"
|
||||
android:text=":"
|
||||
android:textSize="14sp" />
|
||||
|
||||
|
@ -278,10 +278,10 @@
|
|||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:background="@color/listdelimiter" />
|
||||
|
||||
|
||||
|
@ -304,8 +304,8 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:gravity="center_horizontal"
|
||||
android:paddingEnd="2dp"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingEnd="2dp"
|
||||
android:text=":"
|
||||
android:textSize="14sp" />
|
||||
|
||||
|
@ -326,10 +326,10 @@
|
|||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:background="@color/listdelimiter" />
|
||||
|
||||
<LinearLayout
|
||||
|
@ -351,8 +351,8 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
android:gravity="center_horizontal"
|
||||
android:paddingEnd="2dp"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingEnd="2dp"
|
||||
android:text=":"
|
||||
android:textSize="14sp" />
|
||||
|
||||
|
@ -373,10 +373,10 @@
|
|||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:background="@color/listdelimiter" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -425,10 +425,10 @@
|
|||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:background="@color/listdelimiter" />
|
||||
|
||||
|
||||
|
@ -454,10 +454,10 @@
|
|||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:background="@color/listdelimiter" />
|
||||
|
||||
<LinearLayout
|
||||
|
@ -482,10 +482,10 @@
|
|||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:background="@color/listdelimiter" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -512,8 +512,8 @@
|
|||
android:id="@+id/overview_chartMenuButton"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:paddingTop="5dp"
|
||||
app:srcCompat="@drawable/ic_arrow_drop_down_white_24dp" />
|
||||
|
||||
|
@ -526,10 +526,11 @@
|
|||
|
||||
</RelativeLayout>
|
||||
|
||||
<com.jjoe64.graphview.GraphView
|
||||
<LinearLayout
|
||||
android:id="@+id/overview_iobgraph"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="100dp" />
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
|
@ -1813,4 +1813,7 @@
|
|||
<string name="invalidpairing">Invalid pairing information. Requesting new pairing</string>
|
||||
<string name="onconnect">On connect</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>
|
||||
|
|
|
@ -7,7 +7,6 @@ import info.nightscout.androidaps.MainApp
|
|||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.TestBaseWithProfile
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
|
@ -44,7 +43,7 @@ import java.util.*
|
|||
* Created by mike on 18.03.2018.
|
||||
*/
|
||||
@RunWith(PowerMockRunner::class)
|
||||
@PrepareForTest(MainApp::class, ConfigBuilderPlugin::class, ConstraintChecker::class, SP::class, Context::class, OpenAPSMAPlugin::class, OpenAPSAMAPlugin::class, OpenAPSSMBPlugin::class, TreatmentsPlugin::class, TreatmentService::class, VirtualPumpPlugin::class, DetailedBolusInfoStorage::class, GlimpPlugin::class)
|
||||
@PrepareForTest(MainApp::class, ConfigBuilderPlugin::class, ConstraintChecker::class, SP::class, Context::class, OpenAPSAMAPlugin::class, OpenAPSSMBPlugin::class, TreatmentsPlugin::class, TreatmentService::class, VirtualPumpPlugin::class, DetailedBolusInfoStorage::class, GlimpPlugin::class)
|
||||
class ConstraintsCheckerTest : TestBaseWithProfile() {
|
||||
|
||||
@Mock lateinit var activePlugin: ActivePluginProvider
|
||||
|
@ -70,7 +69,6 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
private lateinit var insightPlugin: LocalInsightPlugin
|
||||
private lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin
|
||||
private lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin
|
||||
private lateinit var openAPSMAPlugin: OpenAPSMAPlugin
|
||||
private lateinit var hardLimits: HardLimits
|
||||
|
||||
val injector = HasAndroidInjector {
|
||||
|
@ -119,8 +117,7 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
insightPlugin = LocalInsightPlugin(injector, aapsLogger, rxBus, resourceHelper, treatmentsPlugin, sp, commandQueue, profileFunction, context)
|
||||
openAPSSMBPlugin = OpenAPSSMBPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsPlugin, iobCobCalculatorPlugin, hardLimits)
|
||||
openAPSAMAPlugin = OpenAPSAMAPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsPlugin, iobCobCalculatorPlugin, hardLimits)
|
||||
openAPSMAPlugin = OpenAPSMAPlugin(injector, aapsLogger, rxBus, constraintChecker, resourceHelper, profileFunction, context, activePlugin, treatmentsPlugin, iobCobCalculatorPlugin, hardLimits)
|
||||
safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, treatmentsPlugin)
|
||||
safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, treatmentsPlugin)
|
||||
val constraintsPluginsList = ArrayList<PluginBase?>()
|
||||
constraintsPluginsList.add(safetyPlugin)
|
||||
constraintsPluginsList.add(objectivesPlugin)
|
||||
|
@ -316,7 +313,6 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
`when`(sp.getDouble(R.string.key_openapsma_max_iob, 1.5)).thenReturn(1.5)
|
||||
`when`(sp.getString(R.string.key_age, "")).thenReturn("teenage")
|
||||
openAPSAMAPlugin.setPluginEnabled(PluginType.APS, true)
|
||||
openAPSMAPlugin.setPluginEnabled(PluginType.APS, false)
|
||||
openAPSSMBPlugin.setPluginEnabled(PluginType.APS, false)
|
||||
|
||||
// Apply all limits
|
||||
|
@ -333,7 +329,6 @@ class ConstraintsCheckerTest : TestBaseWithProfile() {
|
|||
`when`(sp.getString(R.string.key_age, "")).thenReturn("teenage")
|
||||
openAPSSMBPlugin.setPluginEnabled(PluginType.APS, true)
|
||||
openAPSAMAPlugin.setPluginEnabled(PluginType.APS, false)
|
||||
openAPSMAPlugin.setPluginEnabled(PluginType.APS, false)
|
||||
|
||||
// Apply all limits
|
||||
val d = constraintChecker.getMaxIOBAllowed()
|
||||
|
|
|
@ -10,7 +10,6 @@ import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
|||
import info.nightscout.androidaps.interfaces.Constraint
|
||||
import info.nightscout.androidaps.interfaces.PumpDescription
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin
|
||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
||||
|
@ -35,7 +34,6 @@ class SafetyPluginTest : TestBaseWithProfile() {
|
|||
@Mock lateinit var sp: SP
|
||||
@Mock lateinit var constraintChecker: ConstraintChecker
|
||||
@Mock lateinit var openAPSAMAPlugin: OpenAPSAMAPlugin
|
||||
@Mock lateinit var openAPSMAPlugin: OpenAPSMAPlugin
|
||||
@Mock lateinit var openAPSSMBPlugin: OpenAPSSMBPlugin
|
||||
@Mock lateinit var sensitivityOref1Plugin: SensitivityOref1Plugin
|
||||
@Mock lateinit var activePlugin: ActivePluginProvider
|
||||
|
@ -75,7 +73,7 @@ class SafetyPluginTest : TestBaseWithProfile() {
|
|||
`when`(activePlugin.activePump).thenReturn(virtualPumpPlugin)
|
||||
`when`(virtualPumpPlugin.pumpDescription).thenReturn(pumpDescription)
|
||||
hardLimits = HardLimits(aapsLogger, rxBus, sp, resourceHelper, context)
|
||||
safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, treatmentsPlugin)
|
||||
safetyPlugin = SafetyPlugin(injector, aapsLogger, resourceHelper, sp, rxBus, constraintChecker, openAPSAMAPlugin, openAPSSMBPlugin, sensitivityOref1Plugin, activePlugin, hardLimits, buildHelper, treatmentsPlugin)
|
||||
}
|
||||
|
||||
@Test fun pumpDescriptionShouldLimitLoopInvocation() {
|
||||
|
|
|
@ -5,10 +5,11 @@ import info.nightscout.androidaps.TestBase
|
|||
import info.nightscout.androidaps.plugins.general.maintenance.formats.*
|
||||
import info.nightscout.androidaps.testing.mockers.AAPSMocker
|
||||
import info.nightscout.androidaps.testing.utils.SingleStringStorage
|
||||
import info.nightscout.androidaps.utils.CryptoUtil
|
||||
import info.nightscout.androidaps.utils.assumeAES256isSupported
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import org.hamcrest.CoreMatchers
|
||||
import org.json.JSONException
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
@ -30,6 +31,8 @@ class EncryptedPrefsFormatTest : TestBase() {
|
|||
@Mock lateinit var resourceHelper: ResourceHelper
|
||||
@Mock lateinit var sp: SP
|
||||
|
||||
var cryptoUtil: CryptoUtil = CryptoUtil(aapsLogger)
|
||||
|
||||
@Before
|
||||
fun mock() {
|
||||
AAPSMocker.prepareMock()
|
||||
|
@ -52,9 +55,11 @@ class EncryptedPrefsFormatTest : TestBase() {
|
|||
"}"
|
||||
|
||||
val storage = SingleStringStorage(frozenPrefs)
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage)
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
|
||||
val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret")
|
||||
|
||||
assumeAES256isSupported(cryptoUtil)
|
||||
|
||||
Assert.assertThat(prefs.values.size, CoreMatchers.`is`(2))
|
||||
Assert.assertThat(prefs.values["key1"], CoreMatchers.`is`("A"))
|
||||
Assert.assertThat(prefs.values["keyB"], CoreMatchers.`is`("2"))
|
||||
|
@ -67,7 +72,7 @@ class EncryptedPrefsFormatTest : TestBase() {
|
|||
@Test
|
||||
fun preferenceSavingTest() {
|
||||
val storage = SingleStringStorage("")
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage)
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
|
||||
val prefs = Prefs(
|
||||
mapOf(
|
||||
"key1" to "A",
|
||||
|
@ -84,7 +89,7 @@ class EncryptedPrefsFormatTest : TestBase() {
|
|||
@Test
|
||||
fun importExportStabilityTest() {
|
||||
val storage = SingleStringStorage("")
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage)
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
|
||||
val prefsIn = Prefs(
|
||||
mapOf(
|
||||
"testpref1" to "--1--",
|
||||
|
@ -97,6 +102,8 @@ class EncryptedPrefsFormatTest : TestBase() {
|
|||
encryptedFormat.savePreferences(AAPSMocker.getMockedFile(), prefsIn, "tajemnica")
|
||||
val prefsOut = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "tajemnica")
|
||||
|
||||
assumeAES256isSupported(cryptoUtil)
|
||||
|
||||
Assert.assertThat(prefsOut.values.size, CoreMatchers.`is`(2))
|
||||
Assert.assertThat(prefsOut.values["testpref1"], CoreMatchers.`is`("--1--"))
|
||||
Assert.assertThat(prefsOut.values["testpref2"], CoreMatchers.`is`("another"))
|
||||
|
@ -121,7 +128,7 @@ class EncryptedPrefsFormatTest : TestBase() {
|
|||
"}"
|
||||
|
||||
val storage = SingleStringStorage(frozenPrefs)
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage)
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
|
||||
val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "it-is-NOT-right-secret")
|
||||
|
||||
Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0))
|
||||
|
@ -148,9 +155,11 @@ class EncryptedPrefsFormatTest : TestBase() {
|
|||
"}"
|
||||
|
||||
val storage = SingleStringStorage(frozenPrefs)
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage)
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
|
||||
val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret")
|
||||
|
||||
assumeAES256isSupported(cryptoUtil)
|
||||
|
||||
// contents were not tampered and we can decrypt them
|
||||
Assert.assertThat(prefs.values.size, CoreMatchers.`is`(2))
|
||||
|
||||
|
@ -173,7 +182,7 @@ class EncryptedPrefsFormatTest : TestBase() {
|
|||
"}"
|
||||
|
||||
val storage = SingleStringStorage(frozenPrefs)
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage)
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
|
||||
val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret")
|
||||
|
||||
Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0))
|
||||
|
@ -188,7 +197,7 @@ class EncryptedPrefsFormatTest : TestBase() {
|
|||
"}"
|
||||
|
||||
val storage = SingleStringStorage(frozenPrefs)
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage)
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
|
||||
val prefs = encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret")
|
||||
|
||||
Assert.assertThat(prefs.values.size, CoreMatchers.`is`(0))
|
||||
|
@ -200,7 +209,7 @@ class EncryptedPrefsFormatTest : TestBase() {
|
|||
val frozenPrefs = "whatever man, i duno care"
|
||||
|
||||
val storage = SingleStringStorage(frozenPrefs)
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage)
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
|
||||
encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret")
|
||||
}
|
||||
|
||||
|
@ -219,7 +228,7 @@ class EncryptedPrefsFormatTest : TestBase() {
|
|||
"}"
|
||||
|
||||
val storage = SingleStringStorage(frozenPrefs)
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, storage)
|
||||
val encryptedFormat = EncryptedPrefsFormat(resourceHelper, cryptoUtil, storage)
|
||||
encryptedFormat.loadPreferences(AAPSMocker.getMockedFile(), "sikret")
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,31 @@
|
|||
package info.nightscout.androidaps.utils
|
||||
|
||||
import info.nightscout.androidaps.TestBase
|
||||
import org.hamcrest.CoreMatchers.containsString
|
||||
import org.hamcrest.CoreMatchers.not
|
||||
import org.junit.Assert
|
||||
import org.junit.Assume.assumeThat
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore
|
||||
import org.powermock.modules.junit4.PowerMockRunner
|
||||
|
||||
// https://stackoverflow.com/questions/52344522/joseexception-couldnt-create-aes-gcm-nopadding-cipher-illegal-key-size
|
||||
// https://stackoverflow.com/questions/47708951/can-aes-256-work-on-android-devices-with-api-level-26
|
||||
// Java prior to Oracle Java 8u161 does not have policy for 256 bit AES - but Android support it
|
||||
// when test is run in Vanilla JVM without policy - Invalid key size exception is thrown
|
||||
fun assumeAES256isSupported(cryptoUtil: CryptoUtil) {
|
||||
cryptoUtil.lastException?.message?.let { exceptionMessage ->
|
||||
assumeThat("Upgrade your testing environment Java (OpenJDK or Java 8u161) and JAVA_HOME - AES 256 is supported by Android so this exception should not happen!", exceptionMessage, not(containsString("key size")))
|
||||
}
|
||||
}
|
||||
|
||||
@PowerMockIgnore("javax.crypto.*")
|
||||
@RunWith(PowerMockRunner::class)
|
||||
class CryptoUtilTest: TestBase() {
|
||||
|
||||
var cryptoUtil: CryptoUtil = CryptoUtil(aapsLogger)
|
||||
|
||||
@Test
|
||||
fun testFixedSaltCrypto() {
|
||||
val salt = byteArrayOf(
|
||||
|
@ -19,30 +34,36 @@ class CryptoUtilTest: TestBase() {
|
|||
|
||||
val password = "thisIsFixedPassword"
|
||||
val payload = "FIXED-PAYLOAD"
|
||||
val encrypted = CryptoUtil.encrypt(password, salt, payload)
|
||||
|
||||
val encrypted = cryptoUtil.encrypt(password, salt, payload)
|
||||
assumeAES256isSupported(cryptoUtil)
|
||||
Assert.assertNotNull(encrypted)
|
||||
val decrypted = CryptoUtil.decrypt(password, salt, encrypted!!)
|
||||
|
||||
val decrypted = cryptoUtil.decrypt(password, salt, encrypted!!)
|
||||
assumeAES256isSupported(cryptoUtil)
|
||||
Assert.assertEquals(decrypted, payload)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testStandardCrypto() {
|
||||
val salt = CryptoUtil.mineSalt()
|
||||
val salt = cryptoUtil.mineSalt()
|
||||
|
||||
val password = "topSikret"
|
||||
val payload = "{what:payloadYouWantToProtect}"
|
||||
val encrypted = CryptoUtil.encrypt(password, salt, payload)
|
||||
|
||||
val encrypted = cryptoUtil.encrypt(password, salt, payload)
|
||||
assumeAES256isSupported(cryptoUtil)
|
||||
Assert.assertNotNull(encrypted)
|
||||
val decrypted = CryptoUtil.decrypt(password, salt, encrypted!!)
|
||||
|
||||
val decrypted = cryptoUtil.decrypt(password, salt, encrypted!!)
|
||||
assumeAES256isSupported(cryptoUtil)
|
||||
Assert.assertEquals(decrypted, payload)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHashVector() {
|
||||
val payload = "{what:payloadYouWantToProtect}"
|
||||
val hash = CryptoUtil.sha256(payload)
|
||||
val hash = cryptoUtil.sha256(payload)
|
||||
Assert.assertEquals(hash, "a1aafe3ed6cc127e6d102ddbc40a205147230e9cfd178daf108c83543bbdcd13")
|
||||
}
|
||||
|
||||
|
@ -51,25 +72,25 @@ class CryptoUtilTest: TestBase() {
|
|||
val payload = "{what:payloadYouWantToProtect}"
|
||||
val password = "topSikret"
|
||||
val expectedHmac = "ea2213953d0f2e55047cae2d23fb4f0de1b805d55e6271efa70d6b85fb692bea" // generated using other HMAC tool
|
||||
val hash = CryptoUtil.hmac256(payload, password)
|
||||
val hash = cryptoUtil.hmac256(payload, password)
|
||||
Assert.assertEquals(hash, expectedHmac)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPlainPasswordCheck() {
|
||||
Assert.assertTrue(CryptoUtil.checkPassword("same", "same"))
|
||||
Assert.assertFalse(CryptoUtil.checkPassword("same", "other"))
|
||||
Assert.assertTrue(cryptoUtil.checkPassword("same", "same"))
|
||||
Assert.assertFalse(cryptoUtil.checkPassword("same", "other"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHashedPasswordCheck() {
|
||||
Assert.assertTrue(CryptoUtil.checkPassword("givenSecret", CryptoUtil.hashPassword("givenSecret")))
|
||||
Assert.assertFalse(CryptoUtil.checkPassword("givenSecret", CryptoUtil.hashPassword("otherSecret")))
|
||||
Assert.assertTrue(cryptoUtil.checkPassword("givenSecret", cryptoUtil.hashPassword("givenSecret")))
|
||||
Assert.assertFalse(cryptoUtil.checkPassword("givenSecret", cryptoUtil.hashPassword("otherSecret")))
|
||||
|
||||
Assert.assertTrue(CryptoUtil.checkPassword("givenHashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
|
||||
Assert.assertFalse(CryptoUtil.checkPassword("givenMashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
|
||||
Assert.assertFalse(CryptoUtil.checkPassword("givenHashToCheck", "hmac:0fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
|
||||
Assert.assertFalse(CryptoUtil.checkPassword("givenHashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:b0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
|
||||
Assert.assertTrue(cryptoUtil.checkPassword("givenHashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
|
||||
Assert.assertFalse(cryptoUtil.checkPassword("givenMashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
|
||||
Assert.assertFalse(cryptoUtil.checkPassword("givenHashToCheck", "hmac:0fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:a0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
|
||||
Assert.assertFalse(cryptoUtil.checkPassword("givenHashToCheck", "hmac:7fe5f9c7b4b97c5d32d5cfad9d07473543a9938dc07af48a46dbbb49f4f68c12:b0c7cee14312bbe31b51359a67f0d2dfdf46813f319180269796f1f617a64be1"))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue