diff --git a/app/build.gradle b/app/build.gradle index 6ecea2b3e1..d4b18b1df0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -192,6 +192,8 @@ dependencies { compile "com.joanzapata.iconify:android-iconify-fontawesome:2.1.1" compile "com.google.android.gms:play-services-wearable:7.5.0" compile(name: "android-edittext-validator-v1.3.4-mod", ext: "aar") + compile(name: "sightparser-release", ext: "aar") + compile("com.google.android:flexbox:0.3.0") { exclude group: "com.android.support" } diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.java b/app/src/main/java/info/nightscout/androidaps/MainApp.java index 02576cb23d..848afb34e5 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.java +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.java @@ -54,6 +54,7 @@ import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin; import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin; import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin; import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin; +import info.nightscout.androidaps.plugins.PumpInsight.InsightPumpPlugin; import info.nightscout.androidaps.plugins.PumpMDI.MDIPlugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin; @@ -129,6 +130,7 @@ public class MainApp extends Application { if (Config.DANAR) pluginsList.add(DanaRv2Plugin.getPlugin()); if (Config.DANAR) pluginsList.add(DanaRSPlugin.getPlugin()); pluginsList.add(CareportalPlugin.getPlugin()); + if (Config.APS) pluginsList.add(InsightPumpPlugin.getPlugin()); if (Config.MDI) pluginsList.add(MDIPlugin.getPlugin()); if (Config.VIRTUALPUMP) pluginsList.add(VirtualPumpPlugin.getPlugin()); if (Config.APS) pluginsList.add(LoopPlugin.getPlugin()); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/InsightPumpFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/InsightPumpFragment.java new file mode 100644 index 0000000000..53b68ebc9a --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/InsightPumpFragment.java @@ -0,0 +1,106 @@ +package info.nightscout.androidaps.plugins.PumpInsight; + + +import android.app.Activity; +import android.os.Bundle; +import android.os.Handler; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.squareup.otto.Subscribe; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.plugins.Common.SubscriberFragment; +import info.nightscout.androidaps.plugins.PumpInsight.connector.Connector; +import info.nightscout.androidaps.plugins.PumpInsight.events.EventInsightPumpUpdateGui; + +import com.crashlytics.android.Crashlytics; + +public class InsightPumpFragment extends SubscriberFragment { + private static Logger log = LoggerFactory.getLogger(InsightPumpFragment.class); + + TextView basaBasalRateView; + TextView tempBasalView; + TextView extendedBolusView; + TextView batteryView; + TextView reservoirView; + TextView statusView; + Connector connector = Connector.get(); + + private static Handler sLoopHandler = new Handler(); + private static Runnable sRefreshLoop = null; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (sRefreshLoop == null) { + sRefreshLoop = new Runnable() { + @Override + public void run() { + updateGUI(); + sLoopHandler.postDelayed(sRefreshLoop, 60 * 1000L); + } + }; + sLoopHandler.postDelayed(sRefreshLoop, 60 * 1000L); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + try { + View view = inflater.inflate(R.layout.insightpump_fragment, container, false); + basaBasalRateView = (TextView) view.findViewById(R.id.insightpump_basabasalrate); + tempBasalView = (TextView) view.findViewById(R.id.insightpump_tempbasal); + extendedBolusView = (TextView) view.findViewById(R.id.insightpump_extendedbolus); + batteryView = (TextView) view.findViewById(R.id.insightpump_battery); + reservoirView = (TextView) view.findViewById(R.id.insightpump_reservoir); + statusView = (TextView) view.findViewById(R.id.insightpump_status); + + return view; + } catch (Exception e) { + Crashlytics.logException(e); + } + + return null; + } + + @Subscribe + public void onStatusEvent(final EventInsightPumpUpdateGui ev) { + updateGUI(); + } + + @Override + protected void updateGUI() { + Activity activity = getActivity(); + if (activity != null && basaBasalRateView != null) + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + InsightPumpPlugin insightPumpPlugin = InsightPumpPlugin.getPlugin(); + basaBasalRateView.setText(insightPumpPlugin.getBaseBasalRate() + "U"); + if (MainApp.getConfigBuilder().isTempBasalInProgress()) { + tempBasalView.setText(MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis()).toStringFull()); + } else { + tempBasalView.setText(""); + } + if (MainApp.getConfigBuilder().isInHistoryExtendedBoluslInProgress()) { + extendedBolusView.setText(MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis()).toString()); + } else { + extendedBolusView.setText(""); + } + batteryView.setText(insightPumpPlugin.batteryPercent + "%"); + reservoirView.setText(insightPumpPlugin.reservoirInUnits + "U"); + + statusView.setText(connector.getLastStatusMessage()); + } + }); + } +} 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 new file mode 100644 index 0000000000..ceff1c1ff3 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/Connector.java @@ -0,0 +1,207 @@ +package info.nightscout.androidaps.plugins.PumpInsight.connector; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.RemoteException; +import android.util.Log; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.plugins.PumpInsight.events.EventInsightPumpUpdateGui; +import sugar.free.sightparser.handling.ServiceConnectionCallback; +import sugar.free.sightparser.handling.SightServiceConnector; +import sugar.free.sightparser.handling.StatusCallback; +import sugar.free.sightparser.pipeline.Status; + +/** + * Created by jamorham on 23/01/2018. + * + * Connects to SightRemote app service using SightParser library + * + * SightRemote and SightParser created by Tebbe Ubben + * + * Original proof of concept SightProxy by jamorham + * + */ + +public class Connector { + + private static final String TAG = "InsightConnector"; + private static final String COMPANION_APP_PACKAGE = "sugar.free.sightremote"; + private static final String STATUS_RECEIVER = "sugar.free.sightparser.handling.StatusCallback"; + private static volatile Connector instance; + private volatile SightServiceConnector serviceConnector; + private volatile Status lastStatus = null; + private volatile long lastStatusTime = -1; + private boolean companionAppInstalled = false; + private StatusCallback statusCallback = new StatusCallback() { + @Override + public void onStatusChange(Status status) { + + synchronized (this) { + log("Status change: " + status); + lastStatus = status; + lastStatusTime = tsl(); + switch (status) { + // TODO automated reactions to change in status + } + MainApp.bus().post(new EventInsightPumpUpdateGui()); + } + } + }; + + private BroadcastReceiver statusReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context ctx, Intent intent) { + log("Receiving broadcast!"); + final String str = intent.getStringExtra("STATUS_MESSAGE"); + try { + statusCallback.onStatusChange(str); + } catch (RemoteException e) { + log("Remote exception: " + e); + } + } + }; + + private ServiceConnectionCallback connectionCallback = new ServiceConnectionCallback() { + @Override + public void onServiceConnected() { + log("On service connected"); + serviceConnector.connect(); + statusCallback.onStatusChange(safeGetStatus()); + } + + @Override + public void onServiceDisconnected() { + log("Disconnected from service"); + } + }; + + private Connector() { + registerReceiver(); + } + + public static Connector get() { + if (instance == null) { + init_instance(); + } + return instance; + } + + private synchronized static void init_instance() { + if (instance == null) { + instance = new Connector(); + } + } + + private static long tsl() { + return System.currentTimeMillis(); + } + + private static boolean isCompanionAppInstalled() { + return checkPackageExists(MainApp.instance(), COMPANION_APP_PACKAGE); + } + + private static boolean checkPackageExists(Context context, String packageName) { + try { + final PackageManager pm = context.getPackageManager(); + final PackageInfo pi = pm.getPackageInfo(packageName, 0); + return pi.packageName.equals(packageName); + } catch (PackageManager.NameNotFoundException e) { + return false; + } catch (Exception e) { + Log.wtf(TAG, "Exception trying to determine packages! " + e); + return false; + } + } + + public static void connectToPump() { + log("Attempting to connect to pump"); + get().getServiceConnector().connect(); + } + + private static void log(String msg) { + android.util.Log.e("PUMPPUMP", msg); + } + + private void registerReceiver() { + try { + MainApp.instance().unregisterReceiver(statusReceiver); + } catch (Exception e) { + // + } + MainApp.instance().registerReceiver(statusReceiver, new IntentFilter(STATUS_RECEIVER)); + } + + public synchronized void init() { + log("init"); + if (serviceConnector == null) { + companionAppInstalled = isCompanionAppInstalled(); + if (companionAppInstalled) { + serviceConnector = new SightServiceConnector(MainApp.instance()); + serviceConnector.addStatusCallback(statusCallback); + serviceConnector.setConnectionCallback(connectionCallback); + serviceConnector.connectToService(); + log("Trying to connect"); + } else { + log("Not trying init due to missing companion app"); + } + } + } + + public SightServiceConnector getServiceConnector() { + init(); + return serviceConnector; + } + + public String getCurrent() { + init(); + return safeGetStatus().toString(); + } + + public Status safeGetStatus() { + if (isConnected()) return serviceConnector.getStatus(); + return Status.DISCONNECTED; + } + + public Status getLastStatus() { + return lastStatus; + } + + public boolean isConnected() { + return serviceConnector != null && serviceConnector.isConnectedToService(); + } + + public boolean isPumpConnected() { + //return isConnected() && serviceConnector.isUseable(); + return isConnected() && getLastStatus() == Status.CONNECTED; + } + + public String getLastStatusMessage() { + + if (!companionAppInstalled) { + return "Companion app does not appear to be installed!"; + } + + if (!isConnected()) { + return "Not connected to companion app!"; + } + + if (lastStatus == null) { + return "Unknown"; + } + + switch (lastStatus) { + default: + return lastStatus.toString(); + } + } + + public boolean lastStatusRecent() { + return true; // TODO evaluate whether current + } + +} diff --git a/app/src/main/res/layout/insightpump_fragment.xml b/app/src/main/res/layout/insightpump_fragment.xml new file mode 100644 index 0000000000..4d1db0eb57 --- /dev/null +++ b/app/src/main/res/layout/insightpump_fragment.xml @@ -0,0 +1,276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ef4478c208..748a5cd017 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -861,5 +861,7 @@ Recovering from connection loss Not enough insulin for bolus left in reservoir Extended bolus delivery error + Insight + Insight diff --git a/app/src/main/res/xml/pref_insightpump.xml b/app/src/main/res/xml/pref_insightpump.xml new file mode 100644 index 0000000000..b760c162aa --- /dev/null +++ b/app/src/main/res/xml/pref_insightpump.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file