diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.java index b7193caf81..ffdce6a99c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.java @@ -156,6 +156,9 @@ public class AutomationPlugin extends PluginBase { @Subscribe public void onEventLocationChange(EventLocationChange e) { eventLocationChange = e; + if (e != null) + log.debug(String.format("Grabbed location: %f %f Provider: %s", e.location.getLatitude(), e.location.getLongitude(), e.location.getProvider())); + processActions(); } @@ -177,6 +180,9 @@ public class AutomationPlugin extends PluginBase { } private synchronized void processActions() { + if (!isEnabled(PluginType.GENERAL)) + return; + if (L.isEnabled(L.AUTOMATION)) log.debug("processActions"); for (AutomationEvent event : getAutomationEvents()) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/ChooseTriggerDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/ChooseTriggerDialog.java index db532ab39b..cd251add31 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/ChooseTriggerDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/ChooseTriggerDialog.java @@ -20,6 +20,7 @@ import info.nightscout.androidaps.R; import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger; import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg; import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerIob; +import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerLocation; import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerProfilePercent; import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerRecurringTime; import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTempTarget; @@ -40,6 +41,7 @@ public class ChooseTriggerDialog extends DialogFragment { add(new TriggerProfilePercent()); add(new TriggerTempTarget()); add(new TriggerWifiSsid()); + add(new TriggerLocation()); }}; private Unbinder mUnbinder; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputButton.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputButton.java new file mode 100644 index 0000000000..6b0406abe0 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputButton.java @@ -0,0 +1,28 @@ +package info.nightscout.androidaps.plugins.general.automation.elements; + +import android.widget.Button; +import android.widget.LinearLayout; + +public class InputButton extends Element { + + String text; + Runnable runnable; + + public InputButton(String text, Runnable runnable) { + this.text = text; + this.runnable = runnable; + } + + @Override + public void addToLayout(LinearLayout root) { + Button button = new Button(root.getContext()); + + button.setText(text); + button.setOnClickListener(view -> { + if (runnable != null) + runnable.run(); + }); + + root.addView(button); + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDouble.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDouble.java new file mode 100644 index 0000000000..9682d004fa --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputDouble.java @@ -0,0 +1,77 @@ +package info.nightscout.androidaps.plugins.general.automation.elements; + +import android.text.Editable; +import android.text.TextWatcher; +import android.widget.LinearLayout; + +import java.text.DecimalFormat; + +import info.nightscout.androidaps.utils.NumberPicker; + +public class InputDouble extends Element { + + final TextWatcher textWatcher = new TextWatcher() { + @Override + public void afterTextChanged(Editable s) { + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + }; + + private double value; + double minValue; + double maxValue; + private double step; + private DecimalFormat decimalFormat; + + NumberPicker numberPicker; + + public InputDouble() { + super(); + } + + public InputDouble(double value, double minValue, double maxValue, double step, DecimalFormat decimalFormat) { + super(); + this.value = value; + this.minValue = minValue; + this.maxValue = maxValue; + this.step = step; + this.decimalFormat = decimalFormat; + } + + public InputDouble(InputDouble another) { + super(); + value = another.getValue(); + minValue = another.minValue; + maxValue = another.maxValue; + step = another.step; + decimalFormat = another.decimalFormat; + } + + + @Override + public void addToLayout(LinearLayout root) { + numberPicker = new NumberPicker(root.getContext(), null); + numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, textWatcher); + numberPicker.setOnValueChangedListener(value -> this.value = value); + root.addView(numberPicker); + } + + public InputDouble setValue(double value) { + this.value = value; + if (numberPicker != null) + numberPicker.setValue(value); + return this; + } + + public double getValue() { + return value; + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/LayoutBuilder.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/LayoutBuilder.java index c73c3b4c25..5853e50be0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/LayoutBuilder.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/LayoutBuilder.java @@ -12,6 +12,11 @@ public class LayoutBuilder { return this; } + public LayoutBuilder add(Element element, boolean condition) { + if (condition) mElements.add(element); + return this; + } + public void build(LinearLayout layout) { for (Element e : mElements) { e.addToLayout(layout); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerLocation.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerLocation.java new file mode 100644 index 0000000000..7ae897f907 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerLocation.java @@ -0,0 +1,169 @@ +package info.nightscout.androidaps.plugins.general.automation.triggers; + +import android.location.Location; +import android.support.v4.app.FragmentManager; +import android.widget.LinearLayout; + +import com.google.common.base.Optional; + +import org.json.JSONException; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.DecimalFormat; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.events.EventLocationChange; +import info.nightscout.androidaps.logging.L; +import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin; +import info.nightscout.androidaps.plugins.general.automation.elements.InputButton; +import info.nightscout.androidaps.plugins.general.automation.elements.InputDouble; +import info.nightscout.androidaps.plugins.general.automation.elements.InputString; +import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement; +import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder; +import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel; +import info.nightscout.androidaps.utils.DateUtil; +import info.nightscout.androidaps.utils.JsonHelper; +import info.nightscout.androidaps.utils.T; + +public class TriggerLocation extends Trigger { + private static Logger log = LoggerFactory.getLogger(L.AUTOMATION); + + InputDouble latitude = new InputDouble(0d, -90d, +90d, 0.000001d, new DecimalFormat("0.000000")); + InputDouble longitude = new InputDouble(0d, -180d, +180d, 0.000001d, new DecimalFormat("0.000000")); + InputDouble distance = new InputDouble(200d, 0, 100000, 10d, new DecimalFormat("0")); + InputString name = new InputString(); + + Runnable buttonAction = () -> { + EventLocationChange event = AutomationPlugin.getPlugin().getEventLocationChange(); + if (event != null) { + latitude.setValue(event.location.getLatitude()); + longitude.setValue(event.location.getLongitude()); + log.debug(String.format("Grabbed location: %f %f", latitude.getValue(), longitude.getValue())); + } + }; + + private InputButton button = new InputButton(MainApp.gs(R.string.currentlocation), buttonAction); + + public TriggerLocation() { + super(); + } + + private TriggerLocation(TriggerLocation triggerLocation) { + super(); + latitude = new InputDouble(triggerLocation.latitude.getValue(), -90d, +90d, 0.00001d, new DecimalFormat("0.00000")); + longitude = new InputDouble(triggerLocation.longitude.getValue(), -180d, +180d, 0.00001d, new DecimalFormat("0.00000")); + distance = new InputDouble(200d, 0, 100000, 10d, new DecimalFormat("0")); + lastRun = triggerLocation.lastRun; + } + + @Override + public synchronized boolean shouldRun() { + EventLocationChange eventLocationChange = AutomationPlugin.getPlugin().getEventLocationChange(); + if (eventLocationChange == null) + return false; + + if (lastRun > DateUtil.now() - T.mins(5).msecs()) + return false; + + Location a = new Location("Trigger"); + a.setLatitude(latitude.getValue()); + a.setLongitude(longitude.getValue()); + double calculatedDistance = eventLocationChange.location.distanceTo(a); + + if (calculatedDistance < distance.getValue()) { + if (L.isEnabled(L.AUTOMATION)) + log.debug("Ready for execution: " + friendlyDescription()); + return true; + } + return false; + } + + @Override + public synchronized String toJSON() { + JSONObject o = new JSONObject(); + try { + o.put("type", TriggerLocation.class.getName()); + JSONObject data = new JSONObject(); + data.put("latitude", latitude.getValue()); + data.put("longitude", longitude.getValue()); + data.put("distance", distance.getValue()); + data.put("name", name.getValue()); + data.put("lastRun", lastRun); + o.put("data", data); + } catch (JSONException e) { + e.printStackTrace(); + } + return o.toString(); + } + + @Override + Trigger fromJSON(String data) { + try { + JSONObject d = new JSONObject(data); + latitude.setValue(JsonHelper.safeGetDouble(d, "latitude")); + longitude.setValue(JsonHelper.safeGetDouble(d, "longitude")); + distance.setValue(JsonHelper.safeGetDouble(d, "distance")); + name.setValue(JsonHelper.safeGetString(d, "name")); + lastRun = JsonHelper.safeGetLong(d, "lastRun"); + } catch (Exception e) { + e.printStackTrace(); + } + return this; + } + + @Override + public int friendlyName() { + return R.string.location; + } + + @Override + public String friendlyDescription() { + return MainApp.gs(R.string.locationis, name.getValue()); + } + + @Override + public Optional icon() { + return Optional.of(R.drawable.remove); // TODO icon + } + + @Override + public Trigger duplicate() { + return new TriggerLocation(this); + } + + + TriggerLocation setLatitude(double value) { + latitude.setValue(value); + return this; + } + + TriggerLocation setLongitude(double value) { + longitude.setValue(value); + return this; + } + + TriggerLocation setdistance(double value) { + distance.setValue(value); + return this; + } + + TriggerLocation lastRun(long lastRun) { + this.lastRun = lastRun; + return this; + } + + @Override + public void generateDialog(LinearLayout root, FragmentManager fragmentManager) { + new LayoutBuilder() + .add(new StaticLabel(R.string.location)) + .add(new LabelWithElement(MainApp.gs(R.string.name_short), "", name)) + .add(new LabelWithElement(MainApp.gs(R.string.latitude_short), "", latitude)) + .add(new LabelWithElement(MainApp.gs(R.string.longitude_short), "", longitude)) + .add(new LabelWithElement(MainApp.gs(R.string.distance_short), "", distance)) + .add(new InputButton(MainApp.gs(R.string.currentlocation), buttonAction), AutomationPlugin.getPlugin().getEventLocationChange() != null) + .build(root); + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/services/LocationService.java b/app/src/main/java/info/nightscout/androidaps/services/LocationService.java index b2d40b02bc..814449e710 100644 --- a/app/src/main/java/info/nightscout/androidaps/services/LocationService.java +++ b/app/src/main/java/info/nightscout/androidaps/services/LocationService.java @@ -18,12 +18,12 @@ import info.nightscout.androidaps.R; import info.nightscout.androidaps.events.EventLocationChange; import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.utils.SP; +import info.nightscout.androidaps.utils.T; public class LocationService extends Service { private static Logger log = LoggerFactory.getLogger(L.LOCATION); private LocationManager mLocationManager = null; - private static final int LOCATION_INTERVAL = 1000; private static final float LOCATION_DISTANCE = 10f; public LocationService() { @@ -33,7 +33,7 @@ public class LocationService extends Service { private class LocationListener implements android.location.LocationListener { Location mLastLocation; - public LocationListener(String provider) { + LocationListener(String provider) { if (L.isEnabled(L.LOCATION)) log.debug("LocationListener " + provider); mLastLocation = new Location(provider); @@ -66,7 +66,7 @@ public class LocationService extends Service { } } - LocationListener mLocationListener = new LocationListener(LocationManager.PASSIVE_PROVIDER); + LocationListener mLocationListener; @Override public IBinder onBind(Intent arg0) { @@ -93,23 +93,23 @@ public class LocationService extends Service { if (SP.getString(R.string.key_location, "NONE").equals("NETWORK")) mLocationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, - LOCATION_INTERVAL, + T.mins(5).msecs(), LOCATION_DISTANCE, - mLocationListener + mLocationListener = new LocationListener(LocationManager.NETWORK_PROVIDER) ); if (SP.getString(R.string.key_location, "NONE").equals("GPS")) mLocationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, - LOCATION_INTERVAL, + T.mins(5).msecs(), LOCATION_DISTANCE, - mLocationListener + mLocationListener = new LocationListener(LocationManager.GPS_PROVIDER) ); if (SP.getString(R.string.key_location, "NONE").equals("PASSIVE")) mLocationManager.requestLocationUpdates( LocationManager.PASSIVE_PROVIDER, - LOCATION_INTERVAL, + T.mins(1).msecs(), LOCATION_DISTANCE, - mLocationListener + mLocationListener = new LocationListener(LocationManager.PASSIVE_PROVIDER) ); } catch (java.lang.SecurityException ex) { log.error("fail to request location update, ignore", ex); @@ -138,7 +138,7 @@ public class LocationService extends Service { private void initializeLocationManager() { if (L.isEnabled(L.LOCATION)) - log.debug("initializeLocationManager - LOCATION_INTERVAL: " + LOCATION_INTERVAL + " LOCATION_DISTANCE: " + LOCATION_DISTANCE); + log.debug("initializeLocationManager - Provider: " + SP.getString(R.string.key_location, "NONE")); if (mLocationManager == null) { mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 93b4a50063..dee0a621f8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1400,6 +1400,13 @@ not exists Temp target %1$s WiFi SSID %1$s %2$s + Current Location + Location + Lat: + Lon: + Dist [m]: + Name: + Location is %1$s %1$d day diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/elements/LayoutBuilderTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/elements/LayoutBuilderTest.java index 9d90cf9178..12b3aa1b25 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/elements/LayoutBuilderTest.java +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/elements/LayoutBuilderTest.java @@ -12,12 +12,24 @@ import info.nightscout.androidaps.MainApp; @RunWith(PowerMockRunner.class) @PrepareForTest({MainApp.class}) public class LayoutBuilderTest { - LayoutBuilder layoutBuilder = new LayoutBuilder(); @Test public void addTest() { + LayoutBuilder layoutBuilder = new LayoutBuilder(); + InputInsulin inputInsulin = new InputInsulin(); layoutBuilder.add(inputInsulin); Assert.assertEquals(1, layoutBuilder.mElements.size()); } + + @Test + public void addConditionalTest() { + LayoutBuilder layoutBuilder = new LayoutBuilder(); + + InputInsulin inputInsulin = new InputInsulin(); + layoutBuilder.add(inputInsulin, true); + Assert.assertEquals(1, layoutBuilder.mElements.size()); + layoutBuilder.add(inputInsulin, false); + Assert.assertEquals(1, layoutBuilder.mElements.size()); + } } \ No newline at end of file