Application is built from plugins. Every plugin must extends Fragment and must implements PluginBase and may implements Interfaces. So declaration looks like:

public class ConfigBuilderFragment extends Fragment implements PluginBase, PumpInterface, ConstraintsInterface

Every plugin must be designed as standalone code. The only edit needed for integration with the rest of app is in MainActivity class and looks like

pluginsList.add(SourceXdripFragment.newInstance());

When plugin needs to cooperate with other plugins it always has to go through ConfigBuilder class. For example to send command to pump:

PumpInterface pump = MainApp.getConfigBuilder().getActivePump();
PumpEnactResult result = pump.deliverTreatment(insulin, carbs);

[[/images/app_desing.png]]

ConfigBuilder itself acts as PumpInterface and ConstraintInterface. So when you call MainApp.getConfigBuilder().getActivePump() ConfigBuilder return itself. Then when you interact with pump ConfigBuilder verifies constraints first and then pass command to selected pump driver.

This allows to add specific constraints to app without touching the rest of code. For example creating and registering this Fragment:

public class BolusConstraint extends Fragment implements PluginBase, ConstraintsInterface {
    @Override
    public boolean isLoopEnabled() {
        return true; // Always enable, limit only things you want
    }

    @Override
    public boolean isClosedModeEnabled() {
        return true; // Always enable, limit only things you want
    }

    @Override
    public boolean isAutosensModeEnabled() {
        return true; // Always enable, limit only things you want
    }

    @Override
    public boolean isAMAModeEnabled() {
        return true; // Always enable, limit only things you want
    }

    @Override
    public APSResult applyBasalConstraints(APSResult request) {
        return request; // Don't change, limit only things you want
    }

    @Override
    public Double applyBasalConstraints(Double absoluteRate) {
        return absoluteRate; // Don't change, limit only things you want
    }

    @Override
    public Integer applyBasalConstraints(Integer percentRate) {
        return percentRate; // Don't change, limit only things you want
    }

    @Override
    public Double applyBolusConstraints(Double insulin) {
        if (insulin > 2d) insulin = 2d;
        return insulin;
    }

    @Override
    public Integer applyCarbsConstraints(Integer carbs) {
        return carbs; // Don't change, limit only things you want
    }

    @Override
    public Double applyMaxIOBConstraints(Double maxIob) {
        return maxIob; // Don't change, limit only things you want
    }

    @Override
    public int getType() {
        return PluginBase.CONSTRAINTS;
    }

    @Override
    public String getName() {
        return "Bolus Constraint";
    }

    @Override
    public boolean isEnabled() {
        return true; // Always enabled and cannot be disabled
    }

    @Override
    public boolean isVisibleInTabs() {
        return false; // No need to have own tab in GUI
    }

    @Override
    public boolean canBeHidden() {
        return true;
    }

    @Override
    public void setFragmentEnabled(boolean fragmentEnabled) {
        // Do nothing, always enabled
    }

    @Override
    public void setFragmentVisible(boolean fragmentVisible) {
        // Do nothing, always hidden
    }
}

we limit maximal bolus to 2U everywhere in app.

ConfigBuilder always goes through all registered ConstraintInterfaces and select most restrictive value before passing command to selected pump driver.

Added pump driver can implement ConstraintInterface too, load max values from pump and provide it as another constraint. GUI then doesn't allow entering higher bolus for example