From d317ec94ad810ff5e2a6354885666904e35bcff0 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Tue, 18 Sep 2018 10:05:19 +0200 Subject: [PATCH 001/115] AutomationPlugin --- .../info/nightscout/androidaps/MainApp.java | 2 ++ .../automation/AutomationFragment.java | 24 ++++++++++++++++ .../general/automation/AutomationPlugin.java | 28 +++++++++++++++++++ .../main/res/layout/automation_fragment.xml | 9 ++++++ app/src/main/res/values/strings.xml | 3 ++ 5 files changed, 66 insertions(+) create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.java create mode 100644 app/src/main/res/layout/automation_fragment.xml diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.java b/app/src/main/java/info/nightscout/androidaps/MainApp.java index 327e451225..e9baabb9ca 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.java +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.java @@ -75,6 +75,7 @@ import info.nightscout.androidaps.plugins.Source.SourceXdripPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.Wear.WearPlugin; import info.nightscout.androidaps.plugins.XDripStatusline.StatuslinePlugin; +import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin; import info.nightscout.androidaps.receivers.DataReceiver; import info.nightscout.androidaps.receivers.KeepAliveReceiver; import info.nightscout.androidaps.receivers.NSAlarmReceiver; @@ -187,6 +188,7 @@ public class MainApp extends Application { pluginsList.add(PersistentNotificationPlugin.getPlugin()); pluginsList.add(NSClientPlugin.getPlugin()); pluginsList.add(MaintenancePlugin.initPlugin(this)); + pluginsList.add(AutomationPlugin.getPlugin()); pluginsList.add(ConfigBuilderPlugin.getPlugin()); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.java new file mode 100644 index 0000000000..0e9eccd84e --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.java @@ -0,0 +1,24 @@ +package info.nightscout.androidaps.plugins.general.automation; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.plugins.Common.SubscriberFragment; + +public class AutomationFragment extends SubscriberFragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.automation_fragment, container, false); + return view; + } + + @Override + protected void updateGUI() { + + } +} 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 new file mode 100644 index 0000000000..86e7ae74b7 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.java @@ -0,0 +1,28 @@ +package info.nightscout.androidaps.plugins.general.automation; + +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.interfaces.PluginDescription; +import info.nightscout.androidaps.interfaces.PluginType; + +public class AutomationPlugin extends PluginBase { + + static AutomationPlugin plugin = null; + + public static AutomationPlugin getPlugin() { + if (plugin == null) + plugin = new AutomationPlugin(); + return plugin; + } + + private AutomationPlugin() { + super(new PluginDescription() + .mainType(PluginType.GENERAL) + .fragmentClass(AutomationFragment.class.getName()) + .pluginName(R.string.automation) + .shortName(R.string.automation_short) + .preferencesId(R.xml.pref_safety) + .description(R.string.automation_description) + ); + } +} diff --git a/app/src/main/res/layout/automation_fragment.xml b/app/src/main/res/layout/automation_fragment.xml new file mode 100644 index 0000000000..64cdf916fb --- /dev/null +++ b/app/src/main/res/layout/automation_fragment.xml @@ -0,0 +1,9 @@ + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7f6067898b..8e74db6510 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1205,6 +1205,9 @@ Minimal request change [%] Loop will popup new change request only if change is bigger than this value. Default value is 20% short_tabtitles + Automation + Auto + User defined automation tasks %1$d day From 4ba1adabf41e26154597e55144ddaaa7f310f5df Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Tue, 18 Sep 2018 10:38:12 +0200 Subject: [PATCH 002/115] TriggerAnd, TriggerOr --- .../general/automation/actions/Trigger.java | 6 +++ .../automation/actions/TriggerAnd.java | 35 ++++++++++++++++++ .../general/automation/actions/TriggerOr.java | 35 ++++++++++++++++++ .../automation/actions/TriggerAndTest.java | 37 +++++++++++++++++++ .../automation/actions/TriggerOrTest.java | 37 +++++++++++++++++++ 5 files changed, 150 insertions(+) create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Trigger.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAnd.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOr.java create mode 100644 app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAndTest.java create mode 100644 app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOrTest.java diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Trigger.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Trigger.java new file mode 100644 index 0000000000..911986b377 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Trigger.java @@ -0,0 +1,6 @@ +package info.nightscout.androidaps.plugins.general.automation.actions; + +public abstract class Trigger { + + abstract boolean shouldRun(); +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAnd.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAnd.java new file mode 100644 index 0000000000..27c8305d86 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAnd.java @@ -0,0 +1,35 @@ +package info.nightscout.androidaps.plugins.general.automation.actions; + +import java.util.ArrayList; +import java.util.List; + +public class TriggerAnd extends Trigger { + + private List list = new ArrayList<>(); + + @Override + synchronized boolean shouldRun() { + boolean result = true; + + for (Trigger t : list) { + result = result && t.shouldRun(); + } + return result; + } + + synchronized void add(Trigger t) { + list.add(t); + } + + synchronized boolean remove(Trigger t) { + return list.remove(t); + } + + int size() { + return list.size(); + } + + Trigger get(int i) { + return list.get(i); + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOr.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOr.java new file mode 100644 index 0000000000..630d967f1f --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOr.java @@ -0,0 +1,35 @@ +package info.nightscout.androidaps.plugins.general.automation.actions; + +import java.util.ArrayList; +import java.util.List; + +public class TriggerOr extends Trigger { + + private List list = new ArrayList<>(); + + @Override + synchronized boolean shouldRun() { + boolean result = false; + + for (Trigger t : list) { + result = result || t.shouldRun(); + } + return result; + } + + synchronized void add(Trigger t) { + list.add(t); + } + + synchronized boolean remove(Trigger t) { + return list.remove(t); + } + + int size() { + return list.size(); + } + + Trigger get(int i) { + return list.get(i); + } +} diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAndTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAndTest.java new file mode 100644 index 0000000000..0dc001ccb9 --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAndTest.java @@ -0,0 +1,37 @@ +package info.nightscout.androidaps.plugins.general.automation.actions; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({}) +public class TriggerAndTest { + + @Test + public void doTests() { + TriggerAnd t = new TriggerAnd(); + TriggerAnd t2 = new TriggerAnd(); + TriggerAnd t3 = new TriggerAnd(); + + Assert.assertTrue(t.size() == 0); + + t.add(t2); + Assert.assertTrue(t.size() == 1); + Assert.assertEquals(t2, t.get(0)); + + t.add(t3); + Assert.assertTrue(t.size() == 2); + Assert.assertEquals(t2, t.get(0)); + Assert.assertEquals(t3, t.get(1)); + + t.remove(t2); + Assert.assertTrue(t.size() == 1); + Assert.assertEquals(t3, t.get(0)); + + Assert.assertTrue(t.shouldRun()); + } +} diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOrTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOrTest.java new file mode 100644 index 0000000000..13322680e6 --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOrTest.java @@ -0,0 +1,37 @@ +package info.nightscout.androidaps.plugins.general.automation.actions; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({}) +public class TriggerOrTest { + + @Test + public void doTests() { + TriggerOr t = new TriggerOr(); + TriggerOr t2 = new TriggerOr(); + TriggerOr t3 = new TriggerOr(); + + Assert.assertTrue(t.size() == 0); + + t.add(t2); + Assert.assertTrue(t.size() == 1); + Assert.assertEquals(t2, t.get(0)); + + t.add(t3); + Assert.assertTrue(t.size() == 2); + Assert.assertEquals(t2, t.get(0)); + Assert.assertEquals(t3, t.get(1)); + + t.remove(t2); + Assert.assertTrue(t.size() == 1); + Assert.assertEquals(t3, t.get(0)); + + Assert.assertFalse(t.shouldRun()); + } +} From ca7e9d2a7f3c4d2997f58f05e61a0308ad74c112 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Tue, 18 Sep 2018 12:32:34 +0200 Subject: [PATCH 003/115] TriggerAnd-Or json saving, loading --- .../general/automation/actions/Trigger.java | 28 ++++++++++++++- .../automation/actions/TriggerAnd.java | 34 +++++++++++++++++++ .../general/automation/actions/TriggerOr.java | 34 +++++++++++++++++++ .../automation/actions/TriggerAndTest.java | 24 ++++++++++++- .../automation/actions/TriggerOrTest.java | 24 ++++++++++++- 5 files changed, 141 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Trigger.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Trigger.java index 911986b377..fbb80d7d65 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Trigger.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Trigger.java @@ -1,6 +1,32 @@ package info.nightscout.androidaps.plugins.general.automation.actions; -public abstract class Trigger { +import org.json.JSONException; +import org.json.JSONObject; + +abstract class Trigger { + + Trigger() { + } + + Trigger(String js) { + fromJSON(js); + } abstract boolean shouldRun(); + abstract String toJSON(); + abstract Trigger fromJSON(String data); + + static Trigger instantiate(JSONObject object) { + try { + String type = object.getString("type"); + String data = object.getString("data"); + Class clazz = Class.forName(type); + return ((Trigger) clazz.newInstance()).fromJSON(data); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | JSONException e) { + e.printStackTrace(); + } + return null; + + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAnd.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAnd.java index 27c8305d86..ec4111c9ce 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAnd.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAnd.java @@ -1,5 +1,9 @@ package info.nightscout.androidaps.plugins.general.automation.actions; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import java.util.ArrayList; import java.util.List; @@ -17,6 +21,36 @@ public class TriggerAnd extends Trigger { return result; } + @Override + synchronized String toJSON() { + JSONObject o = new JSONObject(); + try { + o.put("type", TriggerAnd.class.getName()); + JSONArray array = new JSONArray(); + for (Trigger t : list) { + array.put(t.toJSON()); + } + o.put("data", array.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } + return o.toString(); + } + + @Override + Trigger fromJSON(String data) { + try { + JSONArray array = new JSONArray(data); + for (int i = 0; i < array.length(); i++) { + Trigger newItem = instantiate(new JSONObject(array.getString(i))); + list.add(newItem); + } + } catch (JSONException e) { + e.printStackTrace(); + } + return this; + } + synchronized void add(Trigger t) { list.add(t); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOr.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOr.java index 630d967f1f..45c181cf8b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOr.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOr.java @@ -1,5 +1,9 @@ package info.nightscout.androidaps.plugins.general.automation.actions; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import java.util.ArrayList; import java.util.List; @@ -17,6 +21,36 @@ public class TriggerOr extends Trigger { return result; } + @Override + synchronized String toJSON() { + JSONObject o = new JSONObject(); + try { + o.put("type", TriggerOr.class.getName()); + JSONArray array = new JSONArray(); + for (Trigger t : list) { + array.put(t.toJSON()); + } + o.put("data", array.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } + return o.toString(); + } + + @Override + Trigger fromJSON(String data) { + try { + JSONArray array = new JSONArray(data); + for (int i = 0; i < array.length(); i++) { + Trigger newItem = instantiate(new JSONObject(array.getString(i))); + list.add(newItem); + } + } catch (JSONException e) { + e.printStackTrace(); + } + return this; + } + synchronized void add(Trigger t) { list.add(t); } diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAndTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAndTest.java index 0dc001ccb9..ca226f3d88 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAndTest.java +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAndTest.java @@ -1,5 +1,7 @@ package info.nightscout.androidaps.plugins.general.automation.actions; +import org.json.JSONException; +import org.json.JSONObject; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -28,10 +30,30 @@ public class TriggerAndTest { Assert.assertEquals(t2, t.get(0)); Assert.assertEquals(t3, t.get(1)); - t.remove(t2); + Assert.assertTrue(t.remove(t2)); Assert.assertTrue(t.size() == 1); Assert.assertEquals(t3, t.get(0)); Assert.assertTrue(t.shouldRun()); } + + String empty = "{\"data\":\"[]\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerAnd\"}"; + String oneItem = "{\"data\":\"[\\\"{\\\\\\\"data\\\\\\\":\\\\\\\"[]\\\\\\\",\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerAnd\\\\\\\"}\\\"]\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerAnd\"}"; + + @Test + public void toJSONTest() { + TriggerAnd t = new TriggerAnd(); + Assert.assertEquals(empty, t.toJSON()); + t.add(new TriggerAnd()); + Assert.assertEquals(oneItem, t.toJSON()); + } + @Test + public void fromJSONTest() throws JSONException { + TriggerAnd t = new TriggerAnd(); + t.add(new TriggerAnd()); + + TriggerAnd t2 = (TriggerAnd) Trigger.instantiate(new JSONObject(t.toJSON())); + Assert.assertEquals(1, t2.size()); + Assert.assertTrue(t2.get(0) instanceof TriggerAnd); + } } diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOrTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOrTest.java index 13322680e6..b359e5ca15 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOrTest.java +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOrTest.java @@ -1,5 +1,7 @@ package info.nightscout.androidaps.plugins.general.automation.actions; +import org.json.JSONException; +import org.json.JSONObject; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -28,10 +30,30 @@ public class TriggerOrTest { Assert.assertEquals(t2, t.get(0)); Assert.assertEquals(t3, t.get(1)); - t.remove(t2); + Assert.assertTrue(t.remove(t2)); Assert.assertTrue(t.size() == 1); Assert.assertEquals(t3, t.get(0)); Assert.assertFalse(t.shouldRun()); } + + String empty = "{\"data\":\"[]\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerOr\"}"; + String oneItem = "{\"data\":\"[\\\"{\\\\\\\"data\\\\\\\":\\\\\\\"[]\\\\\\\",\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerOr\\\\\\\"}\\\"]\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerOr\"}"; + + @Test + public void toJSONTest() { + TriggerOr t = new TriggerOr(); + Assert.assertEquals(empty, t.toJSON()); + t.add(new TriggerOr()); + Assert.assertEquals(oneItem, t.toJSON()); + } + @Test + public void fromJSONTest() throws JSONException { + TriggerOr t = new TriggerOr(); + t.add(new TriggerOr()); + + TriggerOr t2 = (TriggerOr) Trigger.instantiate(new JSONObject(t.toJSON())); + Assert.assertEquals(1, t2.size()); + Assert.assertTrue(t2.get(0) instanceof TriggerOr); + } } From 2bf07eb0d4c32cdd98ebc4550e4d1869274aeb9b Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Tue, 18 Sep 2018 20:17:45 +0200 Subject: [PATCH 004/115] TriggerBg --- .../general/automation/AutomationPlugin.java | 6 + .../general/automation/actions/Action.java | 6 + .../automation/actions/AutomationEvent.java | 13 ++ .../general/automation/actions/Trigger.java | 19 +- .../general/automation/actions/TriggerBg.java | 84 ++++++++ .../automation/actions/TriggerTime.java | 188 ++++++++++++++++++ .../java/info/nightscout/utils/DateUtil.java | 4 + .../automation/actions/TriggerBgTest.java | 105 ++++++++++ .../automation/actions/TriggerTimeTest.java | 83 ++++++++ 9 files changed, 503 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/AutomationEvent.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerBg.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerTime.java create mode 100644 app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerBgTest.java create mode 100644 app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerTimeTest.java 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 86e7ae74b7..3bf4042512 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 @@ -1,9 +1,13 @@ package info.nightscout.androidaps.plugins.general.automation; +import java.util.ArrayList; +import java.util.List; + import info.nightscout.androidaps.R; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; +import info.nightscout.androidaps.plugins.general.automation.actions.Action; public class AutomationPlugin extends PluginBase { @@ -15,6 +19,8 @@ public class AutomationPlugin extends PluginBase { return plugin; } + List actions = new ArrayList<>(); + private AutomationPlugin() { super(new PluginDescription() .mainType(PluginType.GENERAL) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java new file mode 100644 index 0000000000..5523edf15f --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java @@ -0,0 +1,6 @@ +package info.nightscout.androidaps.plugins.general.automation.actions; + +public abstract class Action { + + abstract void doAction(); +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/AutomationEvent.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/AutomationEvent.java new file mode 100644 index 0000000000..904cc78a4e --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/AutomationEvent.java @@ -0,0 +1,13 @@ +package info.nightscout.androidaps.plugins.general.automation.actions; + +import java.util.ArrayList; +import java.util.List; + +public class AutomationEvent { + + Trigger trigger; + List actions = new ArrayList<>(); + + AutomationEvent() { + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Trigger.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Trigger.java index fbb80d7d65..cfff99f6ab 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Trigger.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Trigger.java @@ -5,17 +5,26 @@ import org.json.JSONObject; abstract class Trigger { + protected static final int ISLOWER = -2; + protected static final int ISEQUALORLOWER = -1; + protected static final int ISEQUAL = 0; + protected static final int ISEQUALORGREATER = 1; + protected static final int ISGREATER = 2; + + protected static final int NOTAVAILABLE = 10; + Trigger() { } - Trigger(String js) { - fromJSON(js); - } - abstract boolean shouldRun(); + abstract String toJSON(); + abstract Trigger fromJSON(String data); + void notifyAboutRun(long time) { + } + static Trigger instantiate(JSONObject object) { try { String type = object.getString("type"); @@ -27,6 +36,6 @@ abstract class Trigger { } return null; - } + } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerBg.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerBg.java new file mode 100644 index 0000000000..4e945cacfa --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerBg.java @@ -0,0 +1,84 @@ +package info.nightscout.androidaps.plugins.general.automation.actions; + +import org.json.JSONException; +import org.json.JSONObject; + +import info.nightscout.androidaps.data.GlucoseStatus; +import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions; +import info.nightscout.utils.JsonHelper; + +public class TriggerBg extends Trigger { + + double threshold; + int comparator = ISEQUAL; + String units = ProfileFunctions.getInstance().getProfileUnits(); + + @Override + synchronized boolean shouldRun() { + GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData(); + + if (glucoseStatus == null && comparator == NOTAVAILABLE) + return true; + if (glucoseStatus == null) + return false; + + switch (comparator) { + case ISLOWER: + return glucoseStatus.glucose < Profile.toMgdl(threshold, units); + case ISEQUALORLOWER: + return glucoseStatus.glucose <= Profile.toMgdl(threshold, units); + case ISEQUAL: + return glucoseStatus.glucose == Profile.toMgdl(threshold, units); + case ISEQUALORGREATER: + return glucoseStatus.glucose >= Profile.toMgdl(threshold, units); + case ISGREATER: + return glucoseStatus.glucose > Profile.toMgdl(threshold, units); + } + return false; + } + + @Override + synchronized String toJSON() { + JSONObject o = new JSONObject(); + try { + o.put("type", TriggerBg.class.getName()); + JSONObject data = new JSONObject(); + data.put("threshold", threshold); + data.put("comparator", comparator); + data.put("units", units); + o.put("data", data.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } + return o.toString(); + } + + @Override + Trigger fromJSON(String data) { + try { + JSONObject d = new JSONObject(data); + threshold = JsonHelper.safeGetDouble(d, "threshold"); + comparator = JsonHelper.safeGetInt(d, "comparator"); + units = JsonHelper.safeGetString(d, "units"); + } catch (JSONException e) { + e.printStackTrace(); + } + return this; + } + + TriggerBg threshold(double threshold) { + this.threshold = threshold; + return this; + } + + TriggerBg comparator(int comparator) { + this.comparator = comparator; + return this; + } + + TriggerBg units(String units) { + this.units = units; + return this; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerTime.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerTime.java new file mode 100644 index 0000000000..8281edb906 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerTime.java @@ -0,0 +1,188 @@ +package info.nightscout.androidaps.plugins.general.automation.actions; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Calendar; + +import info.nightscout.utils.DateUtil; +import info.nightscout.utils.JsonHelper; +import info.nightscout.utils.T; + +public class TriggerTime extends Trigger { + + long lastRun; + + // Single execution + long runAt; + + // Recurring + boolean recurring; + boolean monday = true; + boolean tuesday = true; + boolean wednesday = true; + boolean thursday = true; + boolean friday = true; + boolean saturday = true; + boolean sunday = true; + int hour; + int minute; + + long validTo; + + @Override + boolean shouldRun() { + if (recurring) { + if (validTo != 0 && DateUtil.now() > validTo) + return false; + Calendar c = Calendar.getInstance(); + int scheduledDayOfWeek = c.get(Calendar.DAY_OF_WEEK); + + Calendar scheduledCal = DateUtil.gregorianCalendar(); + scheduledCal.set(Calendar.HOUR_OF_DAY, hour); + scheduledCal.set(Calendar.MINUTE, minute); + scheduledCal.set(Calendar.SECOND, 0); + long scheduled = scheduledCal.getTimeInMillis(); + + if (monday && scheduledDayOfWeek == Calendar.MONDAY || + tuesday && scheduledDayOfWeek == Calendar.TUESDAY || + wednesday && scheduledDayOfWeek == Calendar.WEDNESDAY || + thursday && scheduledDayOfWeek == Calendar.THURSDAY || + friday && scheduledDayOfWeek == Calendar.FRIDAY || + saturday && scheduledDayOfWeek == Calendar.SATURDAY || + sunday && scheduledDayOfWeek == Calendar.SUNDAY) { + if (DateUtil.now() >= scheduled && DateUtil.now() - scheduled < T.mins(5).msecs()) { + if (lastRun < scheduled) + return true; + } + } + return false; + } else { + long now = DateUtil.now(); + if (now >= runAt && now - runAt < T.mins(5).msecs()) + return true; + return false; + } + } + + @Override + String toJSON() { + JSONObject object = new JSONObject(); + JSONObject data = new JSONObject(); + try { + data.put("lastRun", lastRun); + data.put("runAt", runAt); + data.put("recurring", recurring); + data.put("monday", monday); + data.put("tuesday", tuesday); + data.put("wednesday", wednesday); + data.put("thursday", thursday); + data.put("friday", friday); + data.put("saturday", saturday); + data.put("sunday", sunday); + data.put("hour", hour); + data.put("minute", minute); + data.put("validTo", validTo); + object.put("type", TriggerTime.class.getName()); + object.put("data", data.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } + return object.toString(); + } + + @Override + Trigger fromJSON(String data) { + JSONObject o; + try { + o = new JSONObject(data); + lastRun = JsonHelper.safeGetLong(o, "lastRun"); + runAt = JsonHelper.safeGetLong(o, "runAt"); + recurring = JsonHelper.safeGetBoolean(o, "recurring"); + monday = JsonHelper.safeGetBoolean(o, "monday"); + tuesday = JsonHelper.safeGetBoolean(o, "tuesday"); + wednesday = JsonHelper.safeGetBoolean(o, "wednesday"); + thursday = JsonHelper.safeGetBoolean(o, "thursday"); + friday = JsonHelper.safeGetBoolean(o, "friday"); + saturday = JsonHelper.safeGetBoolean(o, "saturday"); + sunday = JsonHelper.safeGetBoolean(o, "sunday"); + hour = JsonHelper.safeGetInt(o, "hour"); + minute = JsonHelper.safeGetInt(o, "minute"); + validTo = JsonHelper.safeGetLong(o, "validTo"); + } catch (JSONException e) { + e.printStackTrace(); + } + return this; + } + + @Override + void notifyAboutRun(long time) { + lastRun = time; + } + + TriggerTime lastRun(long lastRun) { + this.lastRun = lastRun; + return this; + } + + TriggerTime runAt(long runAt) { + this.runAt = runAt; + return this; + } + + TriggerTime recurring(boolean recurring) { + this.recurring = recurring; + return this; + } + + TriggerTime monday(boolean monday) { + this.monday = monday; + return this; + } + + TriggerTime tuesday(boolean tuesday) { + this.tuesday = tuesday; + return this; + } + + TriggerTime wednesday(boolean wednesday) { + this.wednesday = wednesday; + return this; + } + + TriggerTime thursday(boolean thursday) { + this.thursday = thursday; + return this; + } + + TriggerTime friday(boolean friday) { + this.friday = friday; + return this; + } + + TriggerTime saturday(boolean saturday) { + this.saturday = saturday; + return this; + } + + TriggerTime sunday(boolean sunday) { + this.sunday = sunday; + return this; + } + + TriggerTime validTo(long validTo) { + this.validTo = validTo; + return this; + } + + TriggerTime hour(int hour) { + this.hour = hour; + return this; + } + + TriggerTime minute(int minute) { + this.minute = minute; + return this; + } + +} diff --git a/app/src/main/java/info/nightscout/utils/DateUtil.java b/app/src/main/java/info/nightscout/utils/DateUtil.java index c5d5eed51c..0cf3a6c87a 100644 --- a/app/src/main/java/info/nightscout/utils/DateUtil.java +++ b/app/src/main/java/info/nightscout/utils/DateUtil.java @@ -183,4 +183,8 @@ public class DateUtil { public static long roundDateToSec(long date) { return date - date % 1000; } + + public static GregorianCalendar gregorianCalendar() { + return new GregorianCalendar(); + } } diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerBgTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerBgTest.java new file mode 100644 index 0000000000..7215ee8d3e --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerBgTest.java @@ -0,0 +1,105 @@ +package info.nightscout.androidaps.plugins.general.automation.actions; + +import com.squareup.otto.Bus; + +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.util.ArrayList; +import java.util.List; + +import info.AAPSMocker; +import info.nightscout.androidaps.Constants; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.db.BgReading; +import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions; +import info.nightscout.androidaps.plugins.NSClientInternal.data.NSSgv; +import info.nightscout.utils.DateUtil; +import info.nightscout.utils.T; + +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.powermock.api.mockito.PowerMockito.when; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({MainApp.class, Bus.class, ProfileFunctions.class, DateUtil.class}) +public class TriggerBgTest { + + @Test + public void shouldRunTest() { + when(MainApp.getDbHelper().getBgreadingsDataFromTime(anyLong(), anyBoolean())).thenReturn(generateOneCurrentRecordBgData()); + + TriggerBg t = new TriggerBg().units(Constants.MMOL).threshold(4.1d).comparator(Trigger.ISEQUAL); + Assert.assertFalse(t.shouldRun()); + t = new TriggerBg().units(Constants.MGDL).threshold(214).comparator(Trigger.ISEQUAL); + Assert.assertTrue(t.shouldRun()); + t = new TriggerBg().units(Constants.MGDL).threshold(214).comparator(Trigger.ISEQUALORGREATER); + Assert.assertTrue(t.shouldRun()); + t = new TriggerBg().units(Constants.MGDL).threshold(214).comparator(Trigger.ISEQUALORLOWER); + Assert.assertTrue(t.shouldRun()); + t = new TriggerBg().units(Constants.MGDL).threshold(215).comparator(Trigger.ISEQUAL); + Assert.assertFalse(t.shouldRun()); + t = new TriggerBg().units(Constants.MGDL).threshold(215).comparator(Trigger.ISEQUALORLOWER); + Assert.assertTrue(t.shouldRun()); + t = new TriggerBg().units(Constants.MGDL).threshold(215).comparator(Trigger.ISEQUALORGREATER); + Assert.assertFalse(t.shouldRun()); + t = new TriggerBg().units(Constants.MGDL).threshold(213).comparator(Trigger.ISEQUALORGREATER); + Assert.assertTrue(t.shouldRun()); + t = new TriggerBg().units(Constants.MGDL).threshold(213).comparator(Trigger.ISEQUALORLOWER); + Assert.assertFalse(t.shouldRun()); + + when(MainApp.getDbHelper().getBgreadingsDataFromTime(anyLong(), anyBoolean())).thenReturn(new ArrayList<>()); + t = new TriggerBg().units(Constants.MGDL).threshold(213).comparator(Trigger.ISEQUALORLOWER); + Assert.assertFalse(t.shouldRun()); + t = new TriggerBg().comparator(Trigger.NOTAVAILABLE); + Assert.assertTrue(t.shouldRun()); + } + + String bgJson = "{\"data\":\"{\\\"comparator\\\":0,\\\"threshold\\\":4.1,\\\"units\\\":\\\"mmol\\\"}\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerBg\"}"; + + @Test + public void toJSONTest() { + TriggerBg t = new TriggerBg().units(Constants.MMOL).threshold(4.1d).comparator(Trigger.ISEQUAL); + Assert.assertEquals(bgJson, t.toJSON()); + } + + @Test + public void fromJSONTest() throws JSONException { + TriggerBg t = new TriggerBg().units(Constants.MMOL).threshold(4.1d).comparator(Trigger.ISEQUAL); + + TriggerBg t2 = (TriggerBg) Trigger.instantiate(new JSONObject(t.toJSON())); + Assert.assertEquals(Trigger.ISEQUAL, t2.comparator); + Assert.assertEquals(4.1d, t2.threshold, 0.01d); + Assert.assertEquals(Constants.MMOL, t2.units); + } + + @Before + public void mock() { + AAPSMocker.mockMainApp(); + AAPSMocker.mockBus(); + AAPSMocker.mockDatabaseHelper(); + AAPSMocker.mockProfileFunctions(); + + PowerMockito.mockStatic(DateUtil.class); + when(DateUtil.now()).thenReturn(1514766900000L + T.mins(1).msecs()); + + } + + List generateOneCurrentRecordBgData() { + List list = new ArrayList<>(); + try { + list.add(new BgReading(new NSSgv(new JSONObject("{\"mgdl\":214,\"mills\":1514766900000,\"direction\":\"Flat\"}")))); + } catch (JSONException e) { + e.printStackTrace(); + } + return list; + } + +} diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerTimeTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerTimeTest.java new file mode 100644 index 0000000000..c8a53fa30a --- /dev/null +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerTimeTest.java @@ -0,0 +1,83 @@ +package info.nightscout.androidaps.plugins.general.automation.actions; + +import com.squareup.otto.Bus; + +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.util.GregorianCalendar; + +import info.AAPSMocker; +import info.nightscout.androidaps.MainApp; +import info.nightscout.utils.DateUtil; +import info.nightscout.utils.T; + +import static org.powermock.api.mockito.PowerMockito.when; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({MainApp.class, Bus.class, DateUtil.class, GregorianCalendar.class}) +public class TriggerTimeTest { + + long now = 1514766900000L; + + @Test + public void shouldRunTest() { + + // scheduled 1 min before + TriggerTime t = new TriggerTime().runAt(now - T.mins(1).msecs()); + Assert.assertTrue(t.shouldRun()); + // scheduled 1 min in the future + t = new TriggerTime().runAt(now + T.mins(1).msecs()); + Assert.assertFalse(t.shouldRun()); + + // limit by validTo + t = new TriggerTime().recurring(true).hour(1).minute(34).validTo(1); + Assert.assertFalse(t.shouldRun()); + + // scheduled 1 min before + t = new TriggerTime().recurring(true).hour(1).minute(34); + Assert.assertTrue(t.shouldRun()); + + // already run + t = new TriggerTime().recurring(true).hour(1).minute(34).lastRun(now - 1); + Assert.assertFalse(t.shouldRun()); + + } + + String timeJson = "{\"data\":\"{\\\"saturday\\\":true,\\\"runAt\\\":1514766840000,\\\"lastRun\\\":0,\\\"recurring\\\":false,\\\"thursday\\\":true,\\\"minute\\\":0,\\\"sunday\\\":true,\\\"tuesday\\\":true,\\\"hour\\\":0,\\\"wednesday\\\":true,\\\"friday\\\":true,\\\"monday\\\":true,\\\"validTo\\\":0}\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerTime\"}"; + + @Test + public void toJSONTest() { + TriggerTime t = new TriggerTime().runAt(now - T.mins(1).msecs()); + Assert.assertEquals(timeJson, t.toJSON()); + } + + @Test + public void fromJSONTest() throws JSONException { + TriggerTime t = new TriggerTime().runAt(now - T.mins(1).msecs()); + + TriggerTime t2 = (TriggerTime) Trigger.instantiate(new JSONObject(t.toJSON())); + Assert.assertEquals(now - T.mins(1).msecs(), t2.runAt); + Assert.assertEquals(false, t2.recurring); + } + + @Before + public void mock() { + AAPSMocker.mockMainApp(); + AAPSMocker.mockBus(); + + PowerMockito.mockStatic(DateUtil.class); + when(DateUtil.now()).thenReturn(now); + + GregorianCalendar calendar = new GregorianCalendar(); + calendar.setTimeInMillis(now); + when(DateUtil.gregorianCalendar()).thenReturn(calendar); + } +} From efec01c6e566caf6746db47cce7131f93f31a417 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Tue, 18 Sep 2018 23:17:00 +0200 Subject: [PATCH 005/115] Some Actions --- .../androidaps/data/PumpEnactResult.java | 5 +++ .../PumpInsight/connector/Connector.java | 2 +- .../SmsCommunicatorPlugin.java | 2 ++ .../general/automation/AutomationEvent.java | 16 +++++++++ .../general/automation/AutomationPlugin.java | 2 +- .../general/automation/actions/Action.java | 5 ++- .../automation/actions/ActionLoopDisable.java | 36 +++++++++++++++++++ .../automation/actions/ActionLoopEnable.java | 31 ++++++++++++++++ .../automation/actions/ActionLoopResume.java | 33 +++++++++++++++++ .../automation/actions/ActionLoopSuspend.java | 30 ++++++++++++++++ .../actions/ActionStartTempTarget.java | 33 +++++++++++++++++ .../automation/actions/AutomationEvent.java | 13 ------- .../{actions => triggers}/Trigger.java | 29 +++++++++++++-- .../{actions => triggers}/TriggerAnd.java | 20 ++++++++++- .../{actions => triggers}/TriggerBg.java | 21 +++++++++-- .../{actions => triggers}/TriggerOr.java | 20 ++++++++++- .../{actions => triggers}/TriggerTime.java | 19 +++++++++- app/src/main/res/values-bg/strings.xml | 2 +- app/src/main/res/values-cs/strings.xml | 2 +- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values-es/strings.xml | 2 +- app/src/main/res/values-fr/strings.xml | 2 +- app/src/main/res/values-it/strings.xml | 2 +- app/src/main/res/values-ko/strings.xml | 2 +- app/src/main/res/values-nl/strings.xml | 2 +- app/src/main/res/values-pl/strings.xml | 2 +- app/src/main/res/values-pt/strings.xml | 2 +- app/src/main/res/values-ro/strings.xml | 2 +- app/src/main/res/values-ru/strings.xml | 2 +- app/src/main/res/values-sk/strings.xml | 2 +- app/src/main/res/values-sv/strings.xml | 2 +- app/src/main/res/values-zh/strings.xml | 2 +- app/src/main/res/values/strings.xml | 19 +++++++++- .../{actions => triggers}/TriggerAndTest.java | 10 +++--- .../{actions => triggers}/TriggerBgTest.java | 6 ++-- .../{actions => triggers}/TriggerOrTest.java | 10 +++--- .../TriggerTimeTest.java | 6 ++-- 37 files changed, 344 insertions(+), 54 deletions(-) create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopDisable.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopEnable.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopResume.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopSuspend.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.java delete mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/AutomationEvent.java rename app/src/main/java/info/nightscout/androidaps/plugins/general/automation/{actions => triggers}/Trigger.java (52%) rename app/src/main/java/info/nightscout/androidaps/plugins/general/automation/{actions => triggers}/TriggerAnd.java (75%) rename app/src/main/java/info/nightscout/androidaps/plugins/general/automation/{actions => triggers}/TriggerBg.java (79%) rename app/src/main/java/info/nightscout/androidaps/plugins/general/automation/{actions => triggers}/TriggerOr.java (75%) rename app/src/main/java/info/nightscout/androidaps/plugins/general/automation/{actions => triggers}/TriggerTime.java (91%) rename app/src/test/java/info/nightscout/androidaps/plugins/general/automation/{actions => triggers}/TriggerAndTest.java (79%) rename app/src/test/java/info/nightscout/androidaps/plugins/general/automation/{actions => triggers}/TriggerBgTest.java (95%) rename app/src/test/java/info/nightscout/androidaps/plugins/general/automation/{actions => triggers}/TriggerOrTest.java (79%) rename app/src/test/java/info/nightscout/androidaps/plugins/general/automation/{actions => triggers}/TriggerTimeTest.java (89%) diff --git a/app/src/main/java/info/nightscout/androidaps/data/PumpEnactResult.java b/app/src/main/java/info/nightscout/androidaps/data/PumpEnactResult.java index 404833b77c..280c948a6a 100644 --- a/app/src/main/java/info/nightscout/androidaps/data/PumpEnactResult.java +++ b/app/src/main/java/info/nightscout/androidaps/data/PumpEnactResult.java @@ -48,6 +48,11 @@ public class PumpEnactResult { return this; } + public PumpEnactResult comment(int comment) { + this.comment = MainApp.gs(comment); + return this; + } + public PumpEnactResult duration(int duration) { this.duration = duration; return this; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/Connector.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/Connector.java index fdc2aff0a6..4a90cd92ca 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/Connector.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/Connector.java @@ -421,7 +421,7 @@ public class Connector { } if (lastStatus == null) { - return MainApp.gs(R.string.insight_unknown); + return MainApp.gs(R.string.unknown); } switch (lastStatus) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorPlugin.java index 1d36eea817..e5e1a6c18e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorPlugin.java @@ -242,6 +242,7 @@ public class SmsCommunicatorPlugin extends PluginBase { LoopPlugin loopPlugin = MainApp.getSpecificPlugin(LoopPlugin.class); if (loopPlugin != null && loopPlugin.isEnabled(PluginType.LOOP)) { loopPlugin.setPluginEnabled(PluginType.LOOP, false); + ConfigBuilderPlugin.getPlugin().storeSettings("SMS_LOOP_STOP"); ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() { @Override public void run() { @@ -260,6 +261,7 @@ public class SmsCommunicatorPlugin extends PluginBase { loopPlugin = MainApp.getSpecificPlugin(LoopPlugin.class); if (loopPlugin != null && !loopPlugin.isEnabled(PluginType.LOOP)) { loopPlugin.setPluginEnabled(PluginType.LOOP, true); + ConfigBuilderPlugin.getPlugin().storeSettings("SMS_LOOP_START"); reply = MainApp.gs(R.string.smscommunicator_loophasbeenenabled); sendSMS(new Sms(receivedSms.phoneNumber, reply, System.currentTimeMillis())); MainApp.bus().post(new EventRefreshOverview("SMS_LOOP_START")); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java new file mode 100644 index 0000000000..c0de76ee37 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java @@ -0,0 +1,16 @@ +package info.nightscout.androidaps.plugins.general.automation; + +import java.util.ArrayList; +import java.util.List; + +import info.nightscout.androidaps.plugins.general.automation.actions.Action; +import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger; + +public class AutomationEvent { + + Trigger trigger; + List actions = new ArrayList<>(); + + AutomationEvent() { + } +} 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 3bf4042512..15853a44eb 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 @@ -19,7 +19,7 @@ public class AutomationPlugin extends PluginBase { return plugin; } - List actions = new ArrayList<>(); + List automationEvents = new ArrayList<>(); private AutomationPlugin() { super(new PluginDescription() diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java index 5523edf15f..b74243326e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java @@ -1,6 +1,9 @@ package info.nightscout.androidaps.plugins.general.automation.actions; +import info.nightscout.androidaps.queue.Callback; + public abstract class Action { - abstract void doAction(); + abstract int friendlyName(); + abstract void doAction(Callback callback); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopDisable.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopDisable.java new file mode 100644 index 0000000000..059bdacaf3 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopDisable.java @@ -0,0 +1,36 @@ +package info.nightscout.androidaps.plugins.general.automation.actions; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.PumpEnactResult; +import info.nightscout.androidaps.events.EventRefreshOverview; +import info.nightscout.androidaps.interfaces.PluginType; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.Loop.LoopPlugin; +import info.nightscout.androidaps.queue.Callback; + +public class ActionLoopDisable extends Action { + @Override + int friendlyName() { + return R.string.disableloop; + } + + @Override + void doAction(Callback callback) { + if (LoopPlugin.getPlugin().isEnabled(PluginType.LOOP)) { + LoopPlugin.getPlugin().setPluginEnabled(PluginType.LOOP, false); + ConfigBuilderPlugin.getPlugin().storeSettings("ActionLoopDisable"); + ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() { + @Override + public void run() { + MainApp.bus().post(new EventRefreshOverview("ActionLoopDisable")); + if (callback != null) + callback.result(result).run(); + } + }); + } else { + if (callback != null) + callback.result(new PumpEnactResult().success(true).comment(R.string.alreadydisabled)).run(); + } + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopEnable.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopEnable.java new file mode 100644 index 0000000000..1ef1ec81a6 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopEnable.java @@ -0,0 +1,31 @@ +package info.nightscout.androidaps.plugins.general.automation.actions; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.PumpEnactResult; +import info.nightscout.androidaps.events.EventRefreshOverview; +import info.nightscout.androidaps.interfaces.PluginType; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.Loop.LoopPlugin; +import info.nightscout.androidaps.queue.Callback; + +public class ActionLoopEnable extends Action { + @Override + int friendlyName() { + return R.string.enableloop; + } + + @Override + void doAction(Callback callback) { + if (!LoopPlugin.getPlugin().isEnabled(PluginType.LOOP)) { + LoopPlugin.getPlugin().setPluginEnabled(PluginType.LOOP, true); + ConfigBuilderPlugin.getPlugin().storeSettings("ActionLoopEnable"); + MainApp.bus().post(new EventRefreshOverview("ActionLoopEnable")); + if (callback != null) + callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run(); + } else { + if (callback != null) + callback.result(new PumpEnactResult().success(true).comment(R.string.alreadyenabled)).run(); + } + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopResume.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopResume.java new file mode 100644 index 0000000000..71244c70f4 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopResume.java @@ -0,0 +1,33 @@ +package info.nightscout.androidaps.plugins.general.automation.actions; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.PumpEnactResult; +import info.nightscout.androidaps.events.EventRefreshOverview; +import info.nightscout.androidaps.interfaces.PluginType; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.Loop.LoopPlugin; +import info.nightscout.androidaps.plugins.NSClientInternal.NSUpload; +import info.nightscout.androidaps.queue.Callback; + +public class ActionLoopResume extends Action { + @Override + int friendlyName() { + return R.string.resumeloop; + } + + @Override + void doAction(Callback callback) { + if (LoopPlugin.getPlugin().isSuspended()) { + LoopPlugin.getPlugin().suspendTo(0); + ConfigBuilderPlugin.getPlugin().storeSettings("ActionLoopResume"); + NSUpload.uploadOpenAPSOffline(0); + MainApp.bus().post(new EventRefreshOverview("ActionLoopResume")); + if (callback != null) + callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run(); + } else { + if (callback != null) + callback.result(new PumpEnactResult().success(true).comment(R.string.notsuspended)).run(); + } + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopSuspend.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopSuspend.java new file mode 100644 index 0000000000..eb9ddfd79c --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionLoopSuspend.java @@ -0,0 +1,30 @@ +package info.nightscout.androidaps.plugins.general.automation.actions; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.PumpEnactResult; +import info.nightscout.androidaps.events.EventRefreshOverview; +import info.nightscout.androidaps.plugins.Loop.LoopPlugin; +import info.nightscout.androidaps.queue.Callback; + +public class ActionLoopSuspend extends Action { + int minutes; + + @Override + int friendlyName() { + return R.string.disableloop; + } + + @Override + void doAction(Callback callback) { + if (!LoopPlugin.getPlugin().isSuspended()) { + LoopPlugin.getPlugin().suspendLoop(minutes); + MainApp.bus().post(new EventRefreshOverview("ActionLoopSuspend")); + if (callback != null) + callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run(); + } else { + if (callback != null) + callback.result(new PumpEnactResult().success(true).comment(R.string.alreadysuspended)).run(); + } + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.java new file mode 100644 index 0000000000..8cd8db0f4e --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.java @@ -0,0 +1,33 @@ +package info.nightscout.androidaps.plugins.general.automation.actions; + +import info.nightscout.androidaps.Constants; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.data.PumpEnactResult; +import info.nightscout.androidaps.db.Source; +import info.nightscout.androidaps.db.TempTarget; +import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; +import info.nightscout.androidaps.queue.Callback; +import info.nightscout.utils.DateUtil; + +public class ActionStartTempTarget extends Action { + + double value; + int durationInMinutes; + String reason; + String units = Constants.MGDL; + + @Override + int friendlyName() { + return R.string.starttemptarget; + } + + @Override + void doAction(Callback callback) { + double converted = Profile.toMgdl(value, units); + TempTarget tempTarget = new TempTarget().date(DateUtil.now()).duration(durationInMinutes).reason(reason).source(Source.USER).low(converted).high(converted); + TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget); + if (callback != null) + callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run(); + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/AutomationEvent.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/AutomationEvent.java deleted file mode 100644 index 904cc78a4e..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/AutomationEvent.java +++ /dev/null @@ -1,13 +0,0 @@ -package info.nightscout.androidaps.plugins.general.automation.actions; - -import java.util.ArrayList; -import java.util.List; - -public class AutomationEvent { - - Trigger trigger; - List actions = new ArrayList<>(); - - AutomationEvent() { - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Trigger.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java similarity index 52% rename from app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Trigger.java rename to app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java index cfff99f6ab..8cfa2156d9 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Trigger.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java @@ -1,9 +1,11 @@ -package info.nightscout.androidaps.plugins.general.automation.actions; +package info.nightscout.androidaps.plugins.general.automation.triggers; import org.json.JSONException; import org.json.JSONObject; -abstract class Trigger { +import info.nightscout.androidaps.R; + +public abstract class Trigger { protected static final int ISLOWER = -2; protected static final int ISEQUALORLOWER = -1; @@ -11,7 +13,7 @@ abstract class Trigger { protected static final int ISEQUALORGREATER = 1; protected static final int ISGREATER = 2; - protected static final int NOTAVAILABLE = 10; + protected static final int ISNOTAVAILABLE = 10; Trigger() { } @@ -22,6 +24,10 @@ abstract class Trigger { abstract Trigger fromJSON(String data); + abstract int friendlyName(); + + abstract String friendlyDescription(); + void notifyAboutRun(long time) { } @@ -38,4 +44,21 @@ abstract class Trigger { } + public static int toComparatorString(int comparator) { + switch (comparator) { + case ISLOWER: + return R.string.islower; + case ISEQUALORLOWER: + return R.string.isequalorlower; + case ISEQUAL: + return R.string.isequal; + case ISEQUALORGREATER: + return R.string.isequalorgreater; + case ISGREATER: + return R.string.isgreater; + case ISNOTAVAILABLE: + return R.string.isnotavailable; + } + return R.string.unknown; + } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAnd.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAnd.java similarity index 75% rename from app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAnd.java rename to app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAnd.java index ec4111c9ce..3e791afcc7 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAnd.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAnd.java @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.general.automation.actions; +package info.nightscout.androidaps.plugins.general.automation.triggers; import org.json.JSONArray; import org.json.JSONException; @@ -7,6 +7,8 @@ import org.json.JSONObject; import java.util.ArrayList; import java.util.List; +import info.nightscout.androidaps.R; + public class TriggerAnd extends Trigger { private List list = new ArrayList<>(); @@ -51,6 +53,22 @@ public class TriggerAnd extends Trigger { return this; } + @Override + int friendlyName() { + return R.string.and; + } + + @Override + String friendlyDescription() { + int counter = 0; + StringBuilder result = new StringBuilder(); + for (Trigger t : list) { + if (counter++ > 0) result.append(R.string.and); + result.append(t.friendlyDescription()); + } + return result.toString(); + } + synchronized void add(Trigger t) { list.add(t); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerBg.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java similarity index 79% rename from app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerBg.java rename to app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java index 4e945cacfa..5939502163 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerBg.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java @@ -1,8 +1,10 @@ -package info.nightscout.androidaps.plugins.general.automation.actions; +package info.nightscout.androidaps.plugins.general.automation.triggers; import org.json.JSONException; import org.json.JSONObject; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.GlucoseStatus; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions; @@ -18,7 +20,7 @@ public class TriggerBg extends Trigger { synchronized boolean shouldRun() { GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData(); - if (glucoseStatus == null && comparator == NOTAVAILABLE) + if (glucoseStatus == null && comparator == ISNOTAVAILABLE) return true; if (glucoseStatus == null) return false; @@ -61,12 +63,25 @@ public class TriggerBg extends Trigger { threshold = JsonHelper.safeGetDouble(d, "threshold"); comparator = JsonHelper.safeGetInt(d, "comparator"); units = JsonHelper.safeGetString(d, "units"); - } catch (JSONException e) { + } catch (JSONException e) { e.printStackTrace(); } return this; } + @Override + int friendlyName() { + return R.string.glucose; + } + + @Override + String friendlyDescription() { + if (comparator == Trigger.ISNOTAVAILABLE) + return MainApp.gs(R.string.glucoseisnotavailable); + else + return MainApp.gs(R.string.glucosecompared, Trigger.toComparatorString(comparator), threshold, units); + } + TriggerBg threshold(double threshold) { this.threshold = threshold; return this; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOr.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerOr.java similarity index 75% rename from app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOr.java rename to app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerOr.java index 45c181cf8b..309838b25f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOr.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerOr.java @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.general.automation.actions; +package info.nightscout.androidaps.plugins.general.automation.triggers; import org.json.JSONArray; import org.json.JSONException; @@ -7,6 +7,8 @@ import org.json.JSONObject; import java.util.ArrayList; import java.util.List; +import info.nightscout.androidaps.R; + public class TriggerOr extends Trigger { private List list = new ArrayList<>(); @@ -51,6 +53,22 @@ public class TriggerOr extends Trigger { return this; } + @Override + int friendlyName() { + return R.string.or; + } + + @Override + String friendlyDescription() { + int counter = 0; + StringBuilder result = new StringBuilder(); + for (Trigger t : list) { + if (counter++ > 0) result.append(R.string.or); + result.append(t.friendlyDescription()); + } + return result.toString(); + } + synchronized void add(Trigger t) { list.add(t); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerTime.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.java similarity index 91% rename from app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerTime.java rename to app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.java index 8281edb906..b5f0e6e072 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerTime.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.java @@ -1,10 +1,12 @@ -package info.nightscout.androidaps.plugins.general.automation.actions; +package info.nightscout.androidaps.plugins.general.automation.triggers; import org.json.JSONException; import org.json.JSONObject; import java.util.Calendar; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; import info.nightscout.utils.DateUtil; import info.nightscout.utils.JsonHelper; import info.nightscout.utils.T; @@ -115,6 +117,21 @@ public class TriggerTime extends Trigger { return this; } + @Override + int friendlyName() { + return R.string.time; + } + + @Override + String friendlyDescription() { + if (recurring) { + // TODO + return "Every "; + } else { + return MainApp.gs(R.string.atspecifiedtime, DateUtil.dateAndTimeString(runAt)); + } + } + @Override void notifyAboutRun(long time) { lastRun = time; diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index d57fa1a13c..cb71a297cd 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -796,7 +796,7 @@ Не е свързан към приложението! Приложението изглежда не е инсталирано! Несъвместимо приложение, нужна е версия - Неизвестно + Неизвестно Изчаква се потвърждение на кода Кодът е отхвърлен Свързване с апликацията diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 28fa6eaabd..c68b4b1845 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -796,7 +796,7 @@ Nepřipojen k podpůrné aplikaci! Podpůrná aplikace patrně není nainstalovaná! Nekompatibilní podpůrná aplikace, je požadována verze - Neznámý + Neznámý Čekám na potvrzení kódu Kód odmítnut Připojování aplikace diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 9af4aae9a0..04e65c77e7 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -797,7 +797,7 @@ maxIOB = durchschnittlicher Essensbolus + 3 x maximale Basalrate Keine Verbindung zur Begleit-App! Begleit-App scheint nicht installiert zu sein! Nicht kompatible Begleit-App, wir benötigen Version - Unbekannt + Unbekannt Warte auf Code-Bestätigung Code abgelehnt Verbinden zur App diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index ab5bdf0d2e..65c245f895 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -793,7 +793,7 @@ No conectado a la aplicación companion! ¡La aplicación Companion no parece estar instalada! Aplicación Companion incompatible, necesitamos la versión - Desconocido + Desconocido Esperando código de confirmación Código rechazado Vincular con aplicación diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 58da7d951d..8b05f2d7d5 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -755,7 +755,7 @@ L\'ENSEMBLE DES RISQUES LIÉS À LA QUALITÉ ET À LA PERFORMANCE DU PROGRAMME S Non connectée à l\'application compagnon L\'application compagnon ne semble pas être installée Application compagnon incompatible, besoin d\'une autre version - Inconnue + Inconnue Attente du code de confirmation Code rejeté Liaison avec app diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 3ae470a845..2f114fcdc3 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -796,7 +796,7 @@ Non collegato all\'app! Gruppo dell\'app non sembra essere installato! App incompatibili, abbiamo bisogno di versione - Sconosciuto + Sconosciuto In attesa di conferma Codice rifiutato App di unione diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 634dffe18b..279fce1b79 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -796,7 +796,7 @@ 앱에 연결되지 않았습니다. 앱이 설치되지 않았습니다. 호환되지 않는 앱입니다. 이 버전이 필요합니다 - 알 수 없는 + 알 수 없는 코드 승인 대기중 코드가 거부되었습니다. 앱 연결중 diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 18ad8b2ac6..d2410a8017 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -797,7 +797,7 @@ Stel in en gebruik tijdelijk en standaard tijdelijke streefdoelen (bv. bij sport Niet verbonden met de Companion app! Companion app lijkt niet geïnstalleerd! Incompatiebele Companion app, we hebben deze versie nodig - Onbekend + Onbekend Wacht op confirmatie van code Code geweigerd app koppeling diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 74760d065d..49cbaab98e 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -797,7 +797,7 @@ Brak połączenia z aplikacją towarzyszącą! Aplikacja towarzysząca prawdopodobnie nie jest zainstalowana! Niezgodna aplikacja towarzysząca, potrzebujemy wersji - Nieznany + Nieznany Oczekuję na potwierdzenie kodu Kod odrzucony Wiązanie aplikacji diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index adf8819a74..e9bad5ab5d 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -796,7 +796,7 @@ Nãp conectado com a aplicação acompanhante! Aplicação acompanhante aparentemente não instalada! Aplicação acompanhante incompatível. Versão necessitada - Desconhecido + Desconhecido A aguardar por código de confirmação Codigo rejeitado Associação de aplicação diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index f2e60784be..aaa7e6adf8 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -796,7 +796,7 @@ Aplicația nu este conectată! Aplicația pare să nu fie instalată! Aplicație incompatibila, este necesară versiunea - Necunoscut + Necunoscut Se așteaptă confirmarea codului Cod respins Conectare aplicație diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 18b0a72853..db6a9c61d3 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -796,7 +796,7 @@ Нет подключения к сопутствующему приложению! Сопутствующее приложение по-видимому не установлено! Несовместимое сопутствующее приложение, нужна версия - Неизвестно + Неизвестно Ожидание подтверждения кода Код отклонен Соединение с приложением diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index ca452725a9..0e9aefdc51 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -797,7 +797,7 @@ Nepripojený k sprievodnej aplikácii! Sprievodná aplikácia pravdepodobne nie je nainštalovaná! Nekompatibilná sprievodná aplikácia, je požadovaná verzia - Neznámy + Neznámy Čakám na potvrdenie kódu Kód odmietnutý Pripájanie aplikácie diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 322d206e13..10e3250f2d 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -796,7 +796,7 @@ Inte ansluten till hjälp-app! Hjälp-app verkar inte vara installerad! Inkompatibel hjälp-app. Vi behöver version - Okänd + Okänd Inväntar kodverifiering Kod ej godkänd Appbindning diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index 6dd67b910e..01fa980a86 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -796,7 +796,7 @@ 没有连接到companion app! 好像没有安装companion app! 和companion app不兼容,我们需要版本 - 未知的 + 未知的 正在等待代码确认 代码被拒绝 App绑定中 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8e74db6510..76e8a4bf27 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -893,7 +893,7 @@ Not connected to companion app! Companion app does not appear to be installed! Incompatible companion app, we need version - Unknown + Unknown Waiting for code confirmation Code rejected App binding @@ -1208,6 +1208,23 @@ Automation Auto User defined automation tasks + Already enabled + Already disabled + Already suspended + Resume loop + Not suspended + Start temp target + is lower than + is equal or lower than + is equal to + is equal or greater than + is greater than + is not available + Glucose is not available + Glucose %1$s %2$.2f %3$s + And + Or + At %1$s %1$d day diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAndTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAndTest.java similarity index 79% rename from app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAndTest.java rename to app/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAndTest.java index ca226f3d88..930cf64f89 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerAndTest.java +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAndTest.java @@ -1,14 +1,16 @@ -package info.nightscout.androidaps.plugins.general.automation.actions; +package info.nightscout.androidaps.plugins.general.automation.triggers; import org.json.JSONException; import org.json.JSONObject; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; +import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger; +import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerAnd; + @RunWith(PowerMockRunner.class) @PrepareForTest({}) public class TriggerAndTest { @@ -37,8 +39,8 @@ public class TriggerAndTest { Assert.assertTrue(t.shouldRun()); } - String empty = "{\"data\":\"[]\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerAnd\"}"; - String oneItem = "{\"data\":\"[\\\"{\\\\\\\"data\\\\\\\":\\\\\\\"[]\\\\\\\",\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerAnd\\\\\\\"}\\\"]\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerAnd\"}"; + String empty = "{\"data\":\"[]\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerAnd\"}"; + String oneItem = "{\"data\":\"[\\\"{\\\\\\\"data\\\\\\\":\\\\\\\"[]\\\\\\\",\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerAnd\\\\\\\"}\\\"]\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerAnd\"}"; @Test public void toJSONTest() { diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerBgTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBgTest.java similarity index 95% rename from app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerBgTest.java rename to app/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBgTest.java index 7215ee8d3e..fa6d03ed69 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerBgTest.java +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBgTest.java @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.general.automation.actions; +package info.nightscout.androidaps.plugins.general.automation.triggers; import com.squareup.otto.Bus; @@ -58,11 +58,11 @@ public class TriggerBgTest { when(MainApp.getDbHelper().getBgreadingsDataFromTime(anyLong(), anyBoolean())).thenReturn(new ArrayList<>()); t = new TriggerBg().units(Constants.MGDL).threshold(213).comparator(Trigger.ISEQUALORLOWER); Assert.assertFalse(t.shouldRun()); - t = new TriggerBg().comparator(Trigger.NOTAVAILABLE); + t = new TriggerBg().comparator(Trigger.ISNOTAVAILABLE); Assert.assertTrue(t.shouldRun()); } - String bgJson = "{\"data\":\"{\\\"comparator\\\":0,\\\"threshold\\\":4.1,\\\"units\\\":\\\"mmol\\\"}\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerBg\"}"; + String bgJson = "{\"data\":\"{\\\"comparator\\\":0,\\\"threshold\\\":4.1,\\\"units\\\":\\\"mmol\\\"}\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg\"}"; @Test public void toJSONTest() { diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOrTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerOrTest.java similarity index 79% rename from app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOrTest.java rename to app/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerOrTest.java index b359e5ca15..0417e702aa 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerOrTest.java +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerOrTest.java @@ -1,14 +1,16 @@ -package info.nightscout.androidaps.plugins.general.automation.actions; +package info.nightscout.androidaps.plugins.general.automation.triggers; import org.json.JSONException; import org.json.JSONObject; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; +import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger; +import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerOr; + @RunWith(PowerMockRunner.class) @PrepareForTest({}) public class TriggerOrTest { @@ -37,8 +39,8 @@ public class TriggerOrTest { Assert.assertFalse(t.shouldRun()); } - String empty = "{\"data\":\"[]\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerOr\"}"; - String oneItem = "{\"data\":\"[\\\"{\\\\\\\"data\\\\\\\":\\\\\\\"[]\\\\\\\",\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerOr\\\\\\\"}\\\"]\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerOr\"}"; + String empty = "{\"data\":\"[]\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerOr\"}"; + String oneItem = "{\"data\":\"[\\\"{\\\\\\\"data\\\\\\\":\\\\\\\"[]\\\\\\\",\\\\\\\"type\\\\\\\":\\\\\\\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerOr\\\\\\\"}\\\"]\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerOr\"}"; @Test public void toJSONTest() { diff --git a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerTimeTest.java b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeTest.java similarity index 89% rename from app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerTimeTest.java rename to app/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeTest.java index c8a53fa30a..4aa94e2f8c 100644 --- a/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/actions/TriggerTimeTest.java +++ b/app/src/test/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTimeTest.java @@ -1,4 +1,4 @@ -package info.nightscout.androidaps.plugins.general.automation.actions; +package info.nightscout.androidaps.plugins.general.automation.triggers; import com.squareup.otto.Bus; @@ -16,6 +16,8 @@ import java.util.GregorianCalendar; import info.AAPSMocker; import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger; +import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTime; import info.nightscout.utils.DateUtil; import info.nightscout.utils.T; @@ -51,7 +53,7 @@ public class TriggerTimeTest { } - String timeJson = "{\"data\":\"{\\\"saturday\\\":true,\\\"runAt\\\":1514766840000,\\\"lastRun\\\":0,\\\"recurring\\\":false,\\\"thursday\\\":true,\\\"minute\\\":0,\\\"sunday\\\":true,\\\"tuesday\\\":true,\\\"hour\\\":0,\\\"wednesday\\\":true,\\\"friday\\\":true,\\\"monday\\\":true,\\\"validTo\\\":0}\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.actions.TriggerTime\"}"; + String timeJson = "{\"data\":\"{\\\"saturday\\\":true,\\\"runAt\\\":1514766840000,\\\"lastRun\\\":0,\\\"recurring\\\":false,\\\"thursday\\\":true,\\\"minute\\\":0,\\\"sunday\\\":true,\\\"tuesday\\\":true,\\\"hour\\\":0,\\\"wednesday\\\":true,\\\"friday\\\":true,\\\"monday\\\":true,\\\"validTo\\\":0}\",\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTime\"}"; @Test public void toJSONTest() { From 3eee5b13c75874f8965fc3471c3a4b4819de8573 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Wed, 19 Sep 2018 15:26:58 +0200 Subject: [PATCH 006/115] LocationService --- app/src/main/AndroidManifest.xml | 4 + .../activities/PreferencesActivity.java | 2 + .../events/EventLocationChange.java | 11 ++ .../info/nightscout/androidaps/logging/L.java | 2 + .../general/automation/AutomationPlugin.java | 74 ++++++++- .../androidaps/services/LocationService.java | 146 ++++++++++++++++++ app/src/main/res/values/arrays.xml | 12 ++ app/src/main/res/values/strings.xml | 5 + app/src/main/res/xml/pref_automation.xml | 10 ++ 9 files changed, 264 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/info/nightscout/androidaps/events/EventLocationChange.java create mode 100644 app/src/main/java/info/nightscout/androidaps/services/LocationService.java create mode 100644 app/src/main/res/xml/pref_automation.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 264132de25..ea96e1f18c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,6 +17,7 @@ + @@ -141,6 +142,9 @@ + (); @@ -109,6 +110,7 @@ public class L { logElements.add(new LogElement(DATASERVICE, true)); logElements.add(new LogElement(DATATREATMENTS, true)); logElements.add(new LogElement(EVENTS, false, true)); + logElements.add(new LogElement(LOCATION, true)); logElements.add(new LogElement(NOTIFICATION, true)); logElements.add(new LogElement(NSCLIENT, true)); logElements.add(new LogElement(OVERVIEW, true)); 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 15853a44eb..22526a50df 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 @@ -1,13 +1,25 @@ package info.nightscout.androidaps.plugins.general.automation; +import android.content.Context; +import android.content.Intent; +import android.location.Location; + +import com.squareup.otto.Subscribe; + import java.util.ArrayList; import java.util.List; +import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.events.EventChargingState; +import info.nightscout.androidaps.events.EventLocationChange; +import info.nightscout.androidaps.events.EventNetworkChange; +import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; -import info.nightscout.androidaps.plugins.general.automation.actions.Action; +import info.nightscout.androidaps.plugins.IobCobCalculator.events.EventAutosensCalculationFinished; +import info.nightscout.androidaps.services.LocationService; public class AutomationPlugin extends PluginBase { @@ -20,6 +32,9 @@ public class AutomationPlugin extends PluginBase { } List automationEvents = new ArrayList<>(); + EventLocationChange eventLocationChange; + EventChargingState eventChargingState; + EventNetworkChange eventNetworkChange; private AutomationPlugin() { super(new PluginDescription() @@ -27,8 +42,63 @@ public class AutomationPlugin extends PluginBase { .fragmentClass(AutomationFragment.class.getName()) .pluginName(R.string.automation) .shortName(R.string.automation_short) - .preferencesId(R.xml.pref_safety) + .preferencesId(R.xml.pref_automation) .description(R.string.automation_description) ); } + + @Override + protected void onStart() { + Context context = MainApp.instance().getApplicationContext(); + context.startService(new Intent(context, LocationService.class)); + + MainApp.bus().register(this); + super.onStart(); + } + + @Override + protected void onStop() { + Context context = MainApp.instance().getApplicationContext(); + context.stopService(new Intent(context, LocationService.class)); + + MainApp.bus().unregister(this); + } + + @Subscribe + public void onEventPreferenceChange(EventPreferenceChange e) { + if (e.isChanged(R.string.key_location)) { + Context context = MainApp.instance().getApplicationContext(); + context.stopService(new Intent(context, LocationService.class)); + context.startService(new Intent(context, LocationService.class)); + } + } + + @Subscribe + public void onEventLocationChange(EventLocationChange e) { + eventLocationChange = e; + processActions(); + } + + @Subscribe + public void onEventChargingState(EventChargingState e) { + eventChargingState = e; + processActions(); + } + + @Subscribe + public void onEventNetworkChange(EventNetworkChange e) { + eventNetworkChange = e; + processActions(); + } + + @Subscribe + public void onEventAutosensCalculationFinished(EventAutosensCalculationFinished e) { + processActions(); + } + + // TODO keepalive + + void processActions() { + + } } diff --git a/app/src/main/java/info/nightscout/androidaps/services/LocationService.java b/app/src/main/java/info/nightscout/androidaps/services/LocationService.java new file mode 100644 index 0000000000..2af3593ffa --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/services/LocationService.java @@ -0,0 +1,146 @@ +package info.nightscout.androidaps.services; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.location.Location; +import android.location.LocationManager; +import android.os.Bundle; +import android.os.IBinder; +import android.support.v4.app.ActivityCompat; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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.utils.SP; + +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() { + MainApp.bus().register(this); + } + + private class LocationListener implements android.location.LocationListener { + Location mLastLocation; + + public LocationListener(String provider) { + if (L.isEnabled(L.LOCATION)) + log.debug("LocationListener " + provider); + mLastLocation = new Location(provider); + } + + @Override + public void onLocationChanged(Location location) { + if (L.isEnabled(L.LOCATION)) + log.debug("onLocationChanged: " + location); + mLastLocation.set(location); + MainApp.bus().post(new EventLocationChange(location)); + } + + @Override + public void onProviderDisabled(String provider) { + if (L.isEnabled(L.LOCATION)) + log.debug("onProviderDisabled: " + provider); + } + + @Override + public void onProviderEnabled(String provider) { + if (L.isEnabled(L.LOCATION)) + log.debug("onProviderEnabled: " + provider); + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + if (L.isEnabled(L.LOCATION)) + log.debug("onStatusChanged: " + provider); + } + } + + LocationListener mLocationListener = new LocationListener(LocationManager.PASSIVE_PROVIDER); + + @Override + public IBinder onBind(Intent arg0) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (L.isEnabled(L.LOCATION)) + log.debug("onStartCommand"); + super.onStartCommand(intent, flags, startId); + return START_STICKY; + } + + @Override + public void onCreate() { + + if (L.isEnabled(L.LOCATION)) + log.debug("onCreate"); + + initializeLocationManager(); + + try { + if (SP.getString(R.string.key_location, "NONE").equals("NETWORK")) + mLocationManager.requestLocationUpdates( + LocationManager.NETWORK_PROVIDER, + LOCATION_INTERVAL, + LOCATION_DISTANCE, + mLocationListener + ); + if (SP.getString(R.string.key_location, "NONE").equals("GPS")) + mLocationManager.requestLocationUpdates( + LocationManager.GPS_PROVIDER, + LOCATION_INTERVAL, + LOCATION_DISTANCE, + mLocationListener + ); + if (SP.getString(R.string.key_location, "NONE").equals("PASSIVE")) + mLocationManager.requestLocationUpdates( + LocationManager.PASSIVE_PROVIDER, + LOCATION_INTERVAL, + LOCATION_DISTANCE, + mLocationListener + ); + } catch (java.lang.SecurityException ex) { + log.error("fail to request location update, ignore", ex); + } catch (IllegalArgumentException ex) { + log.error("network provider does not exist, " + ex.getMessage()); + } + } + + @Override + public void onDestroy() { + if (L.isEnabled(L.LOCATION)) + log.debug("onDestroy"); + super.onDestroy(); + MainApp.bus().unregister(this); + if (mLocationManager != null) { + try { + if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + return; + } + mLocationManager.removeUpdates(mLocationListener); + } catch (Exception ex) { + log.error("fail to remove location listener, ignore", ex); + } + } + } + + private void initializeLocationManager() { + if (L.isEnabled(L.LOCATION)) + log.debug("initializeLocationManager - LOCATION_INTERVAL: " + LOCATION_INTERVAL + " LOCATION_DISTANCE: " + LOCATION_DISTANCE); + if (mLocationManager == null) { + mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE); + } + } +} diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 71ed7429bb..7a5f4efc3a 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -114,6 +114,18 @@ @string/yes + + @string/use_passive_location + @string/use_network_location + @string/use_gps_location + + + + PASSIVE + NETWORK + GPS + + Generic AAPS Accu-Chek Spirit diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 76e8a4bf27..607708a77d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1225,6 +1225,11 @@ And Or At %1$s + Use network location + Use GPS location + Use passive location + Location service + location %1$d day diff --git a/app/src/main/res/xml/pref_automation.xml b/app/src/main/res/xml/pref_automation.xml new file mode 100644 index 0000000000..2a590bbaa1 --- /dev/null +++ b/app/src/main/res/xml/pref_automation.xml @@ -0,0 +1,10 @@ + + + + From e32050d565bedc2397ac38684ac25903523c51c8 Mon Sep 17 00:00:00 2001 From: Nico Schmitz Date: Wed, 19 Sep 2018 21:13:02 +0200 Subject: [PATCH 007/115] Replace constants by comparator enum --- .../general/automation/triggers/Trigger.java | 71 ++++++++++++------- .../automation/triggers/TriggerBg.java | 32 +++------ 2 files changed, 57 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java index 8cfa2156d9..20bf93de9c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java @@ -7,13 +7,54 @@ import info.nightscout.androidaps.R; public abstract class Trigger { - protected static final int ISLOWER = -2; - protected static final int ISEQUALORLOWER = -1; - protected static final int ISEQUAL = 0; - protected static final int ISEQUALORGREATER = 1; - protected static final int ISGREATER = 2; + public enum Comparator { + IS_LOWER, + IS_EQUAL_OR_LOWER, + IS_EQUAL, + IS_EQUAL_OR_GREATER, + IS_GREATER, + IS_NOT_AVAILABLE; - protected static final int ISNOTAVAILABLE = 10; + public int getStringRes() { + switch (this) { + case IS_LOWER: + return R.string.islower; + case IS_EQUAL_OR_LOWER: + return R.string.isequalorlower; + case IS_EQUAL: + return R.string.isequal; + case IS_EQUAL_OR_GREATER: + return R.string.isequalorgreater; + case IS_GREATER: + return R.string.isgreater; + case IS_NOT_AVAILABLE: + return R.string.isnotavailable; + default: + return R.string.unknown; + } + } + + public boolean check(T obj1, T obj2) { + if (obj1 == null || obj2 == null) + return this.equals(Comparator.IS_NOT_AVAILABLE); + + int comparison = obj1.compareTo(obj2); + switch (this) { + case IS_LOWER: + return comparison < 0; + case IS_EQUAL_OR_LOWER: + return comparison <= 0; + case IS_EQUAL: + return comparison == 0; + case IS_EQUAL_OR_GREATER: + return comparison >= 0; + case IS_GREATER: + return comparison > 0; + default: + return false; + } + } + } Trigger() { } @@ -43,22 +84,4 @@ public abstract class Trigger { return null; } - - public static int toComparatorString(int comparator) { - switch (comparator) { - case ISLOWER: - return R.string.islower; - case ISEQUALORLOWER: - return R.string.isequalorlower; - case ISEQUAL: - return R.string.isequal; - case ISEQUALORGREATER: - return R.string.isequalorgreater; - case ISGREATER: - return R.string.isgreater; - case ISNOTAVAILABLE: - return R.string.isnotavailable; - } - return R.string.unknown; - } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java index 5939502163..7024eecd3f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java @@ -12,32 +12,20 @@ import info.nightscout.utils.JsonHelper; public class TriggerBg extends Trigger { - double threshold; - int comparator = ISEQUAL; - String units = ProfileFunctions.getInstance().getProfileUnits(); + protected double threshold; + protected Comparator comparator = Comparator.IS_EQUAL; + protected String units = ProfileFunctions.getInstance().getProfileUnits(); @Override synchronized boolean shouldRun() { GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData(); - if (glucoseStatus == null && comparator == ISNOTAVAILABLE) + if (glucoseStatus == null && comparator.equals(Comparator.IS_NOT_AVAILABLE)) return true; if (glucoseStatus == null) return false; - switch (comparator) { - case ISLOWER: - return glucoseStatus.glucose < Profile.toMgdl(threshold, units); - case ISEQUALORLOWER: - return glucoseStatus.glucose <= Profile.toMgdl(threshold, units); - case ISEQUAL: - return glucoseStatus.glucose == Profile.toMgdl(threshold, units); - case ISEQUALORGREATER: - return glucoseStatus.glucose >= Profile.toMgdl(threshold, units); - case ISGREATER: - return glucoseStatus.glucose > Profile.toMgdl(threshold, units); - } - return false; + return comparator.check(glucoseStatus.glucose, Profile.toMgdl(threshold, units)); } @Override @@ -47,7 +35,7 @@ public class TriggerBg extends Trigger { o.put("type", TriggerBg.class.getName()); JSONObject data = new JSONObject(); data.put("threshold", threshold); - data.put("comparator", comparator); + data.put("comparator", comparator.toString()); data.put("units", units); o.put("data", data.toString()); } catch (JSONException e) { @@ -61,7 +49,7 @@ public class TriggerBg extends Trigger { try { JSONObject d = new JSONObject(data); threshold = JsonHelper.safeGetDouble(d, "threshold"); - comparator = JsonHelper.safeGetInt(d, "comparator"); + comparator = Comparator.valueOf(JsonHelper.safeGetString(d, "comparator")); units = JsonHelper.safeGetString(d, "units"); } catch (JSONException e) { e.printStackTrace(); @@ -76,10 +64,10 @@ public class TriggerBg extends Trigger { @Override String friendlyDescription() { - if (comparator == Trigger.ISNOTAVAILABLE) + if (comparator.equals(Comparator.IS_NOT_AVAILABLE)) return MainApp.gs(R.string.glucoseisnotavailable); else - return MainApp.gs(R.string.glucosecompared, Trigger.toComparatorString(comparator), threshold, units); + return MainApp.gs(R.string.glucosecompared, comparator.getStringRes(), threshold, units); } TriggerBg threshold(double threshold) { @@ -87,7 +75,7 @@ public class TriggerBg extends Trigger { return this; } - TriggerBg comparator(int comparator) { + TriggerBg comparator(Comparator comparator) { this.comparator = comparator; return this; } From 4985864343e9b22f0edb8a153a84d05a8e546465 Mon Sep 17 00:00:00 2001 From: Nico Schmitz Date: Wed, 19 Sep 2018 22:27:30 +0200 Subject: [PATCH 008/115] Add title. Generate getters. --- .../general/automation/AutomationEvent.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java index c0de76ee37..8e71c19d6e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java @@ -8,9 +8,23 @@ import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger; public class AutomationEvent { - Trigger trigger; - List actions = new ArrayList<>(); + private Trigger trigger; + private List actions = new ArrayList<>(); + private String title; - AutomationEvent() { + AutomationEvent(String title) { + this.title = title; + } + + public Trigger getTrigger() { + return trigger; + } + + public List getActions() { + return actions; + } + + public String getTitle() { + return title; } } From b5f30a0f462c7ed78333a9884a998c8d95722e39 Mon Sep 17 00:00:00 2001 From: Nico Schmitz Date: Wed, 19 Sep 2018 22:29:35 +0200 Subject: [PATCH 009/115] Add some content to automation plugin fragment --- .../automation/AutomationFragment.java | 78 ++++++++++++++++++- .../general/automation/AutomationPlugin.java | 24 +++++- .../automation/dialogs/EditEventDialog.java | 16 ++++ .../main/res/drawable/ic_add_black_24dp.xml | 9 +++ .../main/res/layout/automation_event_item.xml | 20 +++++ .../main/res/layout/automation_fragment.xml | 25 +++++- 6 files changed, 166 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.java create mode 100644 app/src/main/res/drawable/ic_add_black_24dp.xml create mode 100644 app/src/main/res/layout/automation_event_item.xml diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.java index 0e9eccd84e..7dce538747 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.java @@ -1,24 +1,100 @@ package info.nightscout.androidaps.plugins.general.automation; +import android.app.Activity; import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.FloatingActionButton; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.TextView; + +import java.util.List; import info.nightscout.androidaps.R; import info.nightscout.androidaps.plugins.Common.SubscriberFragment; +import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog; public class AutomationFragment extends SubscriberFragment { + private RecyclerView mEventListView; + private FloatingActionButton mFabAddEvent; + private EventListAdapter mEventListAdapter; + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.automation_fragment, container, false); + + mEventListView = view.findViewById(R.id.eventListView); + mFabAddEvent = view.findViewById(R.id.fabAddEvent); + + mFabAddEvent.setOnClickListener(this::onClickAddEvent); + + final AutomationPlugin plugin = AutomationPlugin.getPlugin(); + mEventListAdapter = new EventListAdapter(plugin.getAutomationEvents()); + mEventListView.setLayoutManager(new LinearLayoutManager(getContext())); + mEventListView.setAdapter(mEventListAdapter); + + updateGUI(); + return view; } @Override protected void updateGUI() { - + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(() -> { + mEventListAdapter.notifyDataSetChanged(); + }); } + + private void onClickAddEvent(View v) { + /*EditEventDialog dialog = EditEventDialog.newInstance(); + FragmentManager manager = getFragmentManager(); + dialog.show(manager, "EditEventDialog");*/ + + final AutomationPlugin plugin = AutomationPlugin.getPlugin(); + plugin.getAutomationEvents().add(new AutomationEvent("Test")); + updateGUI(); + } + + public static class EventListAdapter extends RecyclerView.Adapter { + private final List mEvents; + + EventListAdapter(List events) { + this.mEvents = events; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.automation_event_item, parent, false); + return new ViewHolder(v); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + final AutomationEvent event = mEvents.get(position); + holder.eventTitle.setText(event.getTitle()); + } + + @Override + public int getItemCount() { + return mEvents.size(); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + TextView eventTitle; + + public ViewHolder(View itemView) { + super(itemView); + eventTitle = itemView.findViewById(R.id.viewEventTitle); + } + } + } + } 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 22526a50df..aef640129c 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 @@ -31,10 +31,10 @@ public class AutomationPlugin extends PluginBase { return plugin; } - List automationEvents = new ArrayList<>(); - EventLocationChange eventLocationChange; - EventChargingState eventChargingState; - EventNetworkChange eventNetworkChange; + private final List automationEvents = new ArrayList<>(); + private EventLocationChange eventLocationChange; + private EventChargingState eventChargingState; + private EventNetworkChange eventNetworkChange; private AutomationPlugin() { super(new PluginDescription() @@ -64,6 +64,22 @@ public class AutomationPlugin extends PluginBase { MainApp.bus().unregister(this); } + public List getAutomationEvents() { + return automationEvents; + } + + public EventLocationChange getEventLocationChange() { + return eventLocationChange; + } + + public EventChargingState getEventChargingState() { + return eventChargingState; + } + + public EventNetworkChange getEventNetworkChange() { + return eventNetworkChange; + } + @Subscribe public void onEventPreferenceChange(EventPreferenceChange e) { if (e.isChanged(R.string.key_location)) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.java new file mode 100644 index 0000000000..c7ab2dbf7b --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.java @@ -0,0 +1,16 @@ +package info.nightscout.androidaps.plugins.general.automation.dialogs; + +import android.os.Bundle; +import android.support.v4.app.DialogFragment; + +public class EditEventDialog extends DialogFragment { + public static EditEventDialog newInstance() { + + Bundle args = new Bundle(); + + EditEventDialog fragment = new EditEventDialog(); + fragment.setArguments(args); + + return fragment; + } +} diff --git a/app/src/main/res/drawable/ic_add_black_24dp.xml b/app/src/main/res/drawable/ic_add_black_24dp.xml new file mode 100644 index 0000000000..0258249cc4 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/automation_event_item.xml b/app/src/main/res/layout/automation_event_item.xml new file mode 100644 index 0000000000..92c9ba93bc --- /dev/null +++ b/app/src/main/res/layout/automation_event_item.xml @@ -0,0 +1,20 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/automation_fragment.xml b/app/src/main/res/layout/automation_fragment.xml index 64cdf916fb..4b6ee5c71d 100644 --- a/app/src/main/res/layout/automation_fragment.xml +++ b/app/src/main/res/layout/automation_fragment.xml @@ -1,9 +1,32 @@ + + + + + + + From c60aae863019a23283fe62ca64d798fa44c45628 Mon Sep 17 00:00:00 2001 From: Nico Schmitz Date: Tue, 25 Sep 2018 00:00:09 +0200 Subject: [PATCH 010/115] Work on implementation for automation plugin. - Use butterknife - Import weekdays selector - Implement layout for trigger connection and trigger time - Implement view holders - Implement adapters - Implement dummy code for quick testings - Refactor code --- app/build.gradle | 3 + .../general/automation/AutomationEvent.java | 6 +- .../automation/AutomationFragment.java | 97 +++++++-- .../automation/dialogs/EditEventDialog.java | 80 ++++++- .../general/automation/triggers/Trigger.java | 50 ++++- .../automation/triggers/TriggerAnd.java | 87 -------- .../automation/triggers/TriggerBg.java | 13 +- .../automation/triggers/TriggerConnector.java | 205 ++++++++++++++++++ .../automation/triggers/TriggerOr.java | 87 -------- .../automation/triggers/TriggerTime.java | 191 ++++++++++------ .../res/drawable/border_automation_unit.xml | 7 + .../res/layout/automation_dialog_event.xml | 31 +++ .../main/res/layout/automation_event_item.xml | 20 +- .../main/res/layout/automation_fragment.xml | 1 + .../layout/automation_trigger_connector.xml | 46 ++++ .../res/layout/automation_trigger_time.xml | 14 ++ app/src/main/res/values/strings.xml | 14 ++ .../automation/triggers/TriggerAndTest.java | 3 - .../automation/triggers/TriggerOrTest.java | 3 - 19 files changed, 670 insertions(+), 288 deletions(-) delete mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAnd.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.java delete mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerOr.java create mode 100644 app/src/main/res/drawable/border_automation_unit.xml create mode 100644 app/src/main/res/layout/automation_dialog_event.xml create mode 100644 app/src/main/res/layout/automation_trigger_connector.xml create mode 100644 app/src/main/res/layout/automation_trigger_time.xml diff --git a/app/build.gradle b/app/build.gradle index 1f86c015dd..f56f727cd4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -155,6 +155,7 @@ allprojects { flatDir { dirs 'libs' } + maven { url 'https://jitpack.io' } } } @@ -216,6 +217,8 @@ dependencies { implementation "com.jakewharton:butterknife:${butterknifeVersion}" annotationProcessor "com.jakewharton:butterknife-compiler:${butterknifeVersion}" + implementation 'com.github.DavidProdinger:weekdays-selector:1.0.4' + testImplementation "junit:junit:4.12" testImplementation "org.json:json:20140107" testImplementation "org.mockito:mockito-core:2.7.22" diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java index 8e71c19d6e..f7cd5c6510 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java @@ -12,9 +12,9 @@ public class AutomationEvent { private List actions = new ArrayList<>(); private String title; - AutomationEvent(String title) { - this.title = title; - } + public void setTitle(String title) { this.title = title; } + + public void setTrigger(Trigger trigger) { this.trigger = trigger; } public Trigger getTrigger() { return trigger; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.java index 7dce538747..8efc953bc7 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.java @@ -3,35 +3,38 @@ package info.nightscout.androidaps.plugins.general.automation; import android.app.Activity; import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.design.widget.FloatingActionButton; +import android.support.v4.app.FragmentManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.LinearLayout; import android.widget.TextView; +import java.util.ArrayList; import java.util.List; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; import info.nightscout.androidaps.R; import info.nightscout.androidaps.plugins.Common.SubscriberFragment; import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog; +import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger; public class AutomationFragment extends SubscriberFragment { - private RecyclerView mEventListView; - private FloatingActionButton mFabAddEvent; + @BindView(R.id.eventListView) + RecyclerView mEventListView; + private EventListAdapter mEventListAdapter; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.automation_fragment, container, false); - - mEventListView = view.findViewById(R.id.eventListView); - mFabAddEvent = view.findViewById(R.id.fabAddEvent); - - mFabAddEvent.setOnClickListener(this::onClickAddEvent); + unbinder = ButterKnife.bind(this, view); final AutomationPlugin plugin = AutomationPlugin.getPlugin(); mEventListAdapter = new EventListAdapter(plugin.getAutomationEvents()); @@ -44,7 +47,7 @@ public class AutomationFragment extends SubscriberFragment { } @Override - protected void updateGUI() { + public void updateGUI() { Activity activity = getActivity(); if (activity != null) activity.runOnUiThread(() -> { @@ -52,21 +55,21 @@ public class AutomationFragment extends SubscriberFragment { }); } - private void onClickAddEvent(View v) { - /*EditEventDialog dialog = EditEventDialog.newInstance(); + @OnClick(R.id.fabAddEvent) + void onClickAddEvent(View v) { + EditEventDialog dialog = EditEventDialog.newInstance(new AutomationEvent()); FragmentManager manager = getFragmentManager(); - dialog.show(manager, "EditEventDialog");*/ - - final AutomationPlugin plugin = AutomationPlugin.getPlugin(); - plugin.getAutomationEvents().add(new AutomationEvent("Test")); - updateGUI(); + dialog.show(manager, "EditEventDialog"); } + /** + * RecyclerViewAdapter to display event lists. + */ public static class EventListAdapter extends RecyclerView.Adapter { - private final List mEvents; + private final List mEventList; EventListAdapter(List events) { - this.mEvents = events; + this.mEventList = events; } @NonNull @@ -78,23 +81,71 @@ public class AutomationFragment extends SubscriberFragment { @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - final AutomationEvent event = mEvents.get(position); + final AutomationEvent event = mEventList.get(position); holder.eventTitle.setText(event.getTitle()); + + // TODO: check null + holder.eventDescription.setText(event.getTrigger().friendlyDescription()); } @Override public int getItemCount() { - return mEvents.size(); + return mEventList.size(); } static class ViewHolder extends RecyclerView.ViewHolder { TextView eventTitle; + TextView eventDescription; - public ViewHolder(View itemView) { - super(itemView); - eventTitle = itemView.findViewById(R.id.viewEventTitle); + public ViewHolder(View view) { + super(view); + eventTitle = view.findViewById(R.id.viewEventTitle); + eventDescription = view.findViewById(R.id.viewEventDescription); } } } + /** + * Custom Adapter to display triggers dynamically with nested linear layouts. + */ + public static class TriggerListAdapter { + private final LinearLayout mRootLayout; + private final LayoutInflater mInflater; + private final List mTriggerList; + + public TriggerListAdapter(LayoutInflater inflater, LinearLayout rootLayout, List triggers) { + mRootLayout = rootLayout; + mInflater = inflater; + mTriggerList = triggers; + build(); + } + + public TriggerListAdapter(LayoutInflater inflater, LinearLayout rootLayout, Trigger trigger) { + mRootLayout = rootLayout; + mInflater = inflater; + mTriggerList = new ArrayList<>(); + mTriggerList.add(trigger); + build(); + } + + public void destroy() { + mRootLayout.removeAllViews(); + for(Trigger trigger : mTriggerList) { + trigger.destroyViewHolder(); + } + } + + private void build() { + for(Trigger trigger : mTriggerList) { + Trigger.ViewHolder viewHolder = trigger.createViewHolder(mInflater); + mRootLayout.addView(viewHolder.getView()); + } + } + + public void rebuild() { + destroy(); + build(); + } + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.java index c7ab2dbf7b..fa9150033a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.java @@ -1,16 +1,92 @@ package info.nightscout.androidaps.plugins.general.automation.dialogs; import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.design.widget.TextInputEditText; import android.support.v4.app.DialogFragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import butterknife.Unbinder; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.plugins.general.automation.AutomationEvent; +import info.nightscout.androidaps.plugins.general.automation.AutomationFragment; +import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin; +import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector; +import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTime; public class EditEventDialog extends DialogFragment { - public static EditEventDialog newInstance() { + + private static AutomationEvent mEvent; + + @BindView(R.id.inputEventTitle) + TextInputEditText mEditEventTitle; + + @BindView(R.id.layoutTrigger) + LinearLayout mLayoutTrigger; + + private Unbinder mUnbinder; + private AutomationFragment.TriggerListAdapter mTriggerListAdapter; + + public static EditEventDialog newInstance(AutomationEvent event) { + mEvent = event; Bundle args = new Bundle(); - EditEventDialog fragment = new EditEventDialog(); fragment.setArguments(args); return fragment; } + + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.automation_dialog_event, container, false); + mUnbinder = ButterKnife.bind(this, view); + + // dummy initialization + TriggerConnector to = new TriggerConnector(TriggerConnector.Type.OR); + to.add(new TriggerTime()); + to.add(new TriggerTime()); + TriggerConnector ta = new TriggerConnector(); + ta.add(to); + mEvent.setTrigger(ta); + + // display triggers + mTriggerListAdapter = new AutomationFragment.TriggerListAdapter(getLayoutInflater(), mLayoutTrigger, mEvent.getTrigger()); + + return view; + } + + @Override + public void onDestroyView() { + mTriggerListAdapter.destroy(); + mUnbinder.unbind(); + super.onDestroyView(); + } + + @OnClick(R.id.ok) + public void onButtonOk(View view) { + String title = mEditEventTitle.getText().toString(); + if (title.isEmpty()) return; + + mEvent.setTitle(title); + + + final AutomationPlugin plugin = AutomationPlugin.getPlugin(); + plugin.getAutomationEvents().add(mEvent); + + dismiss(); + } + + @OnClick(R.id.cancel) + public void onButtonCancel(View view) { + dismiss(); + } + + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java index 20bf93de9c..582080ee58 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java @@ -1,8 +1,15 @@ package info.nightscout.androidaps.plugins.general.automation.triggers; +import android.support.annotation.LayoutRes; +import android.support.annotation.StringRes; +import android.view.LayoutInflater; +import android.view.View; + import org.json.JSONException; import org.json.JSONObject; +import butterknife.ButterKnife; +import butterknife.Unbinder; import info.nightscout.androidaps.R; public abstract class Trigger { @@ -15,7 +22,7 @@ public abstract class Trigger { IS_GREATER, IS_NOT_AVAILABLE; - public int getStringRes() { + public @StringRes int getStringRes() { switch (this) { case IS_LOWER: return R.string.islower; @@ -56,18 +63,26 @@ public abstract class Trigger { } } + protected ViewHolder viewHolder = null; + + protected TriggerConnector connector = null; + Trigger() { } - abstract boolean shouldRun(); + public Trigger getConnector() { + return connector; + } + + public abstract boolean shouldRun(); abstract String toJSON(); abstract Trigger fromJSON(String data); - abstract int friendlyName(); + public abstract int friendlyName(); - abstract String friendlyDescription(); + public abstract String friendlyDescription(); void notifyAboutRun(long time) { } @@ -82,6 +97,33 @@ public abstract class Trigger { e.printStackTrace(); } return null; + } + public abstract ViewHolder createViewHolder(LayoutInflater inflater); + + public ViewHolder getViewHolder() { + return viewHolder; + } + + public void destroyViewHolder() { + if (viewHolder != null) { + viewHolder.destroy(); + } + } + + public static abstract class ViewHolder { + final View view; + final Unbinder unbinder; + + public ViewHolder(LayoutInflater inflater, @LayoutRes int layout) { + view = inflater.inflate(layout, null); + unbinder = ButterKnife.bind(this, view); + } + + public void destroy() { + unbinder.unbind(); + } + + public View getView() { return view; } } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAnd.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAnd.java deleted file mode 100644 index 3e791afcc7..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerAnd.java +++ /dev/null @@ -1,87 +0,0 @@ -package info.nightscout.androidaps.plugins.general.automation.triggers; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.List; - -import info.nightscout.androidaps.R; - -public class TriggerAnd extends Trigger { - - private List list = new ArrayList<>(); - - @Override - synchronized boolean shouldRun() { - boolean result = true; - - for (Trigger t : list) { - result = result && t.shouldRun(); - } - return result; - } - - @Override - synchronized String toJSON() { - JSONObject o = new JSONObject(); - try { - o.put("type", TriggerAnd.class.getName()); - JSONArray array = new JSONArray(); - for (Trigger t : list) { - array.put(t.toJSON()); - } - o.put("data", array.toString()); - } catch (JSONException e) { - e.printStackTrace(); - } - return o.toString(); - } - - @Override - Trigger fromJSON(String data) { - try { - JSONArray array = new JSONArray(data); - for (int i = 0; i < array.length(); i++) { - Trigger newItem = instantiate(new JSONObject(array.getString(i))); - list.add(newItem); - } - } catch (JSONException e) { - e.printStackTrace(); - } - return this; - } - - @Override - int friendlyName() { - return R.string.and; - } - - @Override - String friendlyDescription() { - int counter = 0; - StringBuilder result = new StringBuilder(); - for (Trigger t : list) { - if (counter++ > 0) result.append(R.string.and); - result.append(t.friendlyDescription()); - } - return result.toString(); - } - - synchronized void add(Trigger t) { - list.add(t); - } - - synchronized boolean remove(Trigger t) { - return list.remove(t); - } - - int size() { - return list.size(); - } - - Trigger get(int i) { - return list.get(i); - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java index 7024eecd3f..2a91f2ddd6 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java @@ -1,5 +1,7 @@ package info.nightscout.androidaps.plugins.general.automation.triggers; +import android.view.LayoutInflater; + import org.json.JSONException; import org.json.JSONObject; @@ -17,7 +19,7 @@ public class TriggerBg extends Trigger { protected String units = ProfileFunctions.getInstance().getProfileUnits(); @Override - synchronized boolean shouldRun() { + public synchronized boolean shouldRun() { GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData(); if (glucoseStatus == null && comparator.equals(Comparator.IS_NOT_AVAILABLE)) @@ -58,18 +60,23 @@ public class TriggerBg extends Trigger { } @Override - int friendlyName() { + public int friendlyName() { return R.string.glucose; } @Override - String friendlyDescription() { + public String friendlyDescription() { if (comparator.equals(Comparator.IS_NOT_AVAILABLE)) return MainApp.gs(R.string.glucoseisnotavailable); else return MainApp.gs(R.string.glucosecompared, comparator.getStringRes(), threshold, units); } + @Override + public ViewHolder createViewHolder(LayoutInflater inflater) { + return null; + } + TriggerBg threshold(double threshold) { this.threshold = threshold; return this; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.java new file mode 100644 index 0000000000..0e3528dc02 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.java @@ -0,0 +1,205 @@ +package info.nightscout.androidaps.plugins.general.automation.triggers; + +import android.support.annotation.StringRes; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.OnClick; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.plugins.general.automation.AutomationFragment; +import info.nightscout.utils.JsonHelper; + +public class TriggerConnector extends Trigger { + public enum Type { + AND, + OR; + + public boolean apply(boolean a, boolean b) { + switch (this) { + case AND: + return a && b; + case OR: + return a || b; + } + return false; + } + + public @StringRes int getStringRes() { + switch (this) { + case OR: + return R.string.or; + + default: + case AND: + return R.string.and; + } + } + } + + protected List list = new ArrayList<>(); + private Type connectorType; + + public TriggerConnector() { + connectorType = Type.AND; + } + + public TriggerConnector(Type connectorType) { + this.connectorType = connectorType; + } + + public void changeConnectorType(Type type) { this.connectorType = type; } + + public Type getConnectorType() { return connectorType; } + + public synchronized void add(Trigger t) { + list.add(t); + t.connector = this; + } + + public synchronized boolean remove(Trigger t) { + return list.remove(t); + } + + public int size() { + return list.size(); + } + + public Trigger get(int i) { + return list.get(i); + } + + @Override + public synchronized boolean shouldRun() { + boolean result = false; + + for (Trigger t : list) { + result = connectorType.apply(result, t.shouldRun()); + } + return result; + } + + @Override + synchronized String toJSON() { + JSONObject o = new JSONObject(); + try { + o.put("type", TriggerConnector.class.getName()); + JSONObject data = new JSONObject(); + data.put("connectorType", connectorType.toString()); + JSONArray array = new JSONArray(); + for (Trigger t : list) { + array.put(t.toJSON()); + } + data.put("triggerList", array); + o.put("data", data); + } catch (JSONException e) { + e.printStackTrace(); + } + return o.toString(); + } + + @Override + Trigger fromJSON(String data) { + try { + JSONObject d = new JSONObject(data); + connectorType = Type.valueOf(JsonHelper.safeGetString(d, "connectorType")); + JSONArray array = d.getJSONArray("triggerList"); + for (int i = 0; i < array.length(); i++) { + Trigger newItem = instantiate(new JSONObject(array.getString(i))); + add(newItem); + } + } catch (JSONException e) { + e.printStackTrace(); + } + return this; + } + + @Override + public int friendlyName() { + return connectorType.getStringRes(); + } + + @Override + public String friendlyDescription() { + int counter = 0; + StringBuilder result = new StringBuilder(); + for (Trigger t : list) { + if (counter++ > 0) result.append(friendlyName()); + result.append(t.friendlyDescription()); + } + return result.toString(); + } + + @Override + public ViewHolder createViewHolder(LayoutInflater inflater) { + ViewHolder v = new ViewHolder(inflater); + viewHolder = v; + return v; + } + + + class ViewHolder extends Trigger.ViewHolder { + + @BindView(R.id.triggerListLayout) + LinearLayout triggerListLayout; + + @BindView(R.id.title) + TextView titleView; + + AutomationFragment.TriggerListAdapter adapter; + + public ViewHolder(LayoutInflater inflater) { + super(inflater, R.layout.automation_trigger_connector); + titleView.setText(friendlyName()); + adapter = new AutomationFragment.TriggerListAdapter(inflater, triggerListLayout, list); + } + + @OnClick(R.id.buttonRemove) + public void onButtonClickRemove(View view) { + if (connector != null) { + connector.remove(TriggerConnector.this); + ((TriggerConnector.ViewHolder)connector.getViewHolder()).adapter.rebuild(); + } else { + // no parent + list.clear(); + adapter.rebuild(); + } + } + + @OnClick(R.id.buttonAddAnd) + public void onButtonClickAnd(View view) { + addTrigger(new TriggerTime(), Type.AND); + } + + @OnClick(R.id.buttonAddOr) + public void onButtonClickOr(View view) { + addTrigger(new TriggerTime(), Type.OR); + } + + private void addTrigger(Trigger trigger, Type connection) { + if (getConnectorType().equals(connection)) { + add(trigger); + } else { + TriggerConnector t = new TriggerConnector(connection); + t.add(trigger); + add(t); + } + adapter.rebuild(); + } + + @Override + public void destroy() { + adapter.destroy(); + super.destroy(); + } + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerOr.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerOr.java deleted file mode 100644 index 309838b25f..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerOr.java +++ /dev/null @@ -1,87 +0,0 @@ -package info.nightscout.androidaps.plugins.general.automation.triggers; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.List; - -import info.nightscout.androidaps.R; - -public class TriggerOr extends Trigger { - - private List list = new ArrayList<>(); - - @Override - synchronized boolean shouldRun() { - boolean result = false; - - for (Trigger t : list) { - result = result || t.shouldRun(); - } - return result; - } - - @Override - synchronized String toJSON() { - JSONObject o = new JSONObject(); - try { - o.put("type", TriggerOr.class.getName()); - JSONArray array = new JSONArray(); - for (Trigger t : list) { - array.put(t.toJSON()); - } - o.put("data", array.toString()); - } catch (JSONException e) { - e.printStackTrace(); - } - return o.toString(); - } - - @Override - Trigger fromJSON(String data) { - try { - JSONArray array = new JSONArray(data); - for (int i = 0; i < array.length(); i++) { - Trigger newItem = instantiate(new JSONObject(array.getString(i))); - list.add(newItem); - } - } catch (JSONException e) { - e.printStackTrace(); - } - return this; - } - - @Override - int friendlyName() { - return R.string.or; - } - - @Override - String friendlyDescription() { - int counter = 0; - StringBuilder result = new StringBuilder(); - for (Trigger t : list) { - if (counter++ > 0) result.append(R.string.or); - result.append(t.friendlyDescription()); - } - return result.toString(); - } - - synchronized void add(Trigger t) { - list.add(t); - } - - synchronized boolean remove(Trigger t) { - return list.remove(t); - } - - int size() { - return list.size(); - } - - Trigger get(int i) { - return list.get(i); - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.java index b5f0e6e072..b18236569b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.java @@ -1,10 +1,18 @@ package info.nightscout.androidaps.plugins.general.automation.triggers; +import android.support.annotation.StringRes; +import android.view.LayoutInflater; + +import com.dpro.widgets.WeekdaysPicker; + import org.json.JSONException; import org.json.JSONObject; +import java.util.ArrayList; import java.util.Calendar; +import java.util.List; +import butterknife.BindView; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.utils.DateUtil; @@ -13,6 +21,68 @@ import info.nightscout.utils.T; public class TriggerTime extends Trigger { + public enum DayOfWeek { + MONDAY, + TUESDAY, + WEDNESDAY, + THURSDAY, + FRIDAY, + SATURDAY, + SUNDAY; + + private static final int[] calendarInts = new int[] { + Calendar.MONDAY, + Calendar.TUESDAY, + Calendar.WEDNESDAY, + Calendar.THURSDAY, + Calendar.FRIDAY, + Calendar.SATURDAY, + Calendar.SUNDAY + }; + + private static final int[] fullNames = new int[] { + R.string.weekday_monday, + R.string.weekday_tuesday, + R.string.weekday_wednesday, + R.string.weekday_thursday, + R.string.weekday_friday, + R.string.weekday_saturday, + R.string.weekday_sunday + }; + + private static final int[] shortNames = new int[] { + R.string.weekday_monday_short, + R.string.weekday_tuesday_short, + R.string.weekday_wednesday_short, + R.string.weekday_thursday_short, + R.string.weekday_friday_short, + R.string.weekday_saturday_short, + R.string.weekday_sunday_short + }; + + public int toCalendarInt() { + return calendarInts[ordinal()]; + } + + public static DayOfWeek fromCalendarInt(int day) { + for(int i = 0; i < calendarInts.length; ++i) { + if (calendarInts[i] == day) + return values()[i]; + } + return null; + } + + public @StringRes int getFullName() { + return fullNames[ordinal()]; + } + + public @StringRes int getShortName() { + return shortNames[ordinal()]; + } + } + + private final boolean[] weekdays = new boolean[DayOfWeek.values().length]; + long lastRun; // Single execution @@ -20,20 +90,28 @@ public class TriggerTime extends Trigger { // Recurring boolean recurring; - boolean monday = true; - boolean tuesday = true; - boolean wednesday = true; - boolean thursday = true; - boolean friday = true; - boolean saturday = true; - boolean sunday = true; int hour; int minute; long validTo; + public TriggerTime() { + for(DayOfWeek day : DayOfWeek.values()) { + set(day, true); + } + } + + public TriggerTime set(DayOfWeek day, boolean value) { + weekdays[day.ordinal()] = value; + return this; + } + + public boolean isSet(DayOfWeek day) { + return weekdays[day.ordinal()]; + } + @Override - boolean shouldRun() { + public boolean shouldRun() { if (recurring) { if (validTo != 0 && DateUtil.now() > validTo) return false; @@ -46,13 +124,7 @@ public class TriggerTime extends Trigger { scheduledCal.set(Calendar.SECOND, 0); long scheduled = scheduledCal.getTimeInMillis(); - if (monday && scheduledDayOfWeek == Calendar.MONDAY || - tuesday && scheduledDayOfWeek == Calendar.TUESDAY || - wednesday && scheduledDayOfWeek == Calendar.WEDNESDAY || - thursday && scheduledDayOfWeek == Calendar.THURSDAY || - friday && scheduledDayOfWeek == Calendar.FRIDAY || - saturday && scheduledDayOfWeek == Calendar.SATURDAY || - sunday && scheduledDayOfWeek == Calendar.SUNDAY) { + if (isSet(DayOfWeek.fromCalendarInt(scheduledDayOfWeek))) { if (DateUtil.now() >= scheduled && DateUtil.now() - scheduled < T.mins(5).msecs()) { if (lastRun < scheduled) return true; @@ -75,13 +147,9 @@ public class TriggerTime extends Trigger { data.put("lastRun", lastRun); data.put("runAt", runAt); data.put("recurring", recurring); - data.put("monday", monday); - data.put("tuesday", tuesday); - data.put("wednesday", wednesday); - data.put("thursday", thursday); - data.put("friday", friday); - data.put("saturday", saturday); - data.put("sunday", sunday); + for(int i = 0; i < weekdays.length; ++i) { + data.put(DayOfWeek.values()[i].name(), weekdays[i]); + } data.put("hour", hour); data.put("minute", minute); data.put("validTo", validTo); @@ -101,13 +169,9 @@ public class TriggerTime extends Trigger { lastRun = JsonHelper.safeGetLong(o, "lastRun"); runAt = JsonHelper.safeGetLong(o, "runAt"); recurring = JsonHelper.safeGetBoolean(o, "recurring"); - monday = JsonHelper.safeGetBoolean(o, "monday"); - tuesday = JsonHelper.safeGetBoolean(o, "tuesday"); - wednesday = JsonHelper.safeGetBoolean(o, "wednesday"); - thursday = JsonHelper.safeGetBoolean(o, "thursday"); - friday = JsonHelper.safeGetBoolean(o, "friday"); - saturday = JsonHelper.safeGetBoolean(o, "saturday"); - sunday = JsonHelper.safeGetBoolean(o, "sunday"); + for(int i = 0; i < weekdays.length; ++i) { + weekdays[i] = JsonHelper.safeGetBoolean(o, DayOfWeek.values()[i].name()); + } hour = JsonHelper.safeGetInt(o, "hour"); minute = JsonHelper.safeGetInt(o, "minute"); validTo = JsonHelper.safeGetLong(o, "validTo"); @@ -118,12 +182,12 @@ public class TriggerTime extends Trigger { } @Override - int friendlyName() { + public int friendlyName() { return R.string.time; } @Override - String friendlyDescription() { + public String friendlyDescription() { if (recurring) { // TODO return "Every "; @@ -152,41 +216,6 @@ public class TriggerTime extends Trigger { return this; } - TriggerTime monday(boolean monday) { - this.monday = monday; - return this; - } - - TriggerTime tuesday(boolean tuesday) { - this.tuesday = tuesday; - return this; - } - - TriggerTime wednesday(boolean wednesday) { - this.wednesday = wednesday; - return this; - } - - TriggerTime thursday(boolean thursday) { - this.thursday = thursday; - return this; - } - - TriggerTime friday(boolean friday) { - this.friday = friday; - return this; - } - - TriggerTime saturday(boolean saturday) { - this.saturday = saturday; - return this; - } - - TriggerTime sunday(boolean sunday) { - this.sunday = sunday; - return this; - } - TriggerTime validTo(long validTo) { this.validTo = validTo; return this; @@ -202,4 +231,34 @@ public class TriggerTime extends Trigger { return this; } + @Override + public ViewHolder createViewHolder(LayoutInflater inflater) { + ViewHolder v = new ViewHolder(inflater); + viewHolder = v; + return v; + } + + class ViewHolder extends Trigger.ViewHolder { + + @BindView(R.id.weekdays) + WeekdaysPicker weekdaysPicker; + + public ViewHolder(LayoutInflater inflater) { + super(inflater, R.layout.automation_trigger_time); + + List selectedDays = new ArrayList<>(); + for(int i = 0; i < weekdays.length; ++i) { + DayOfWeek day = DayOfWeek.values()[i]; + boolean selected = weekdays[i]; + if (selected) selectedDays.add(day.toCalendarInt()); + } + weekdaysPicker.setSelectedDays(selectedDays); + + weekdaysPicker.setOnWeekdaysChangeListener((view, i, list) -> { + set(DayOfWeek.fromCalendarInt(i), list.contains(i)); + }); + } + + } + } diff --git a/app/src/main/res/drawable/border_automation_unit.xml b/app/src/main/res/drawable/border_automation_unit.xml new file mode 100644 index 0000000000..6ac70390ae --- /dev/null +++ b/app/src/main/res/drawable/border_automation_unit.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/automation_dialog_event.xml b/app/src/main/res/layout/automation_dialog_event.xml new file mode 100644 index 0000000000..3b49181008 --- /dev/null +++ b/app/src/main/res/layout/automation_dialog_event.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/automation_event_item.xml b/app/src/main/res/layout/automation_event_item.xml index 92c9ba93bc..dc80aeaf15 100644 --- a/app/src/main/res/layout/automation_event_item.xml +++ b/app/src/main/res/layout/automation_event_item.xml @@ -1,20 +1,26 @@ - + android:layout_height="wrap_content" + android:orientation="vertical" + android:layout_marginBottom="8dp" + android:layout_marginEnd="8dp" + android:layout_marginStart="8dp" + android:layout_marginTop="8dp"> - \ No newline at end of file + + + \ No newline at end of file diff --git a/app/src/main/res/layout/automation_fragment.xml b/app/src/main/res/layout/automation_fragment.xml index 4b6ee5c71d..a43225cb44 100644 --- a/app/src/main/res/layout/automation_fragment.xml +++ b/app/src/main/res/layout/automation_fragment.xml @@ -1,3 +1,4 @@ + + + + + + + + + +