diff --git a/app/libs/sightparser-release.aar b/app/libs/sightparser-release.aar index 302b9e836d..1f0c16ee34 100644 Binary files a/app/libs/sightparser-release.aar and b/app/libs/sightparser-release.aar differ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fc9190475e..798c858a10 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -32,11 +32,10 @@ android:icon="${appIcon}" android:label="@string/app_name" android:supportsRtl="true" - android:theme="@style/AppTheme"> + android:theme="@style/AppTheme.NoActionBar"> - @@ -172,7 +171,10 @@ android:name=".setupwizard.SetupWizardActivity" android:configChanges="orientation|keyboardHidden|screenSize" android:theme="@style/AppTheme.SetupWizard" - android:label="@string/title_activity_setup_wizard"> + android:label="@string/title_activity_setup_wizard" /> + + \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.java b/app/src/main/java/info/nightscout/androidaps/MainActivity.java index 9d869cdde6..538f51a82d 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.java @@ -1,30 +1,35 @@ package info.nightscout.androidaps; -import android.app.Activity; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Rect; -import android.os.Build; import android.os.Bundle; +import android.os.PersistableBundle; import android.os.PowerManager; +import android.support.annotation.Nullable; +import android.support.design.widget.NavigationView; +import android.support.design.widget.TabLayout; import android.support.v4.app.ActivityCompat; import android.support.v4.view.ViewPager; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.PopupMenu; +import android.support.v7.widget.Toolbar; import android.text.SpannableString; import android.text.method.LinkMovementMethod; import android.text.util.Linkify; -import android.view.MenuInflater; +import android.util.Log; +import android.util.TypedValue; +import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; -import android.widget.ImageButton; +import android.widget.LinearLayout; import android.widget.TextView; import com.joanzapata.iconify.Iconify; @@ -37,7 +42,6 @@ import org.slf4j.LoggerFactory; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventFeatureRunning; -import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventRefreshGui; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; @@ -45,7 +49,6 @@ import info.nightscout.androidaps.plugins.Food.FoodPlugin; import info.nightscout.androidaps.plugins.Overview.events.EventSetWakeLock; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.setupwizard.SetupWizardActivity; -import info.nightscout.androidaps.tabs.SlidingTabLayout; import info.nightscout.androidaps.tabs.TabPageAdapter; import info.nightscout.utils.AndroidPermission; import info.nightscout.utils.ImportExportPrefs; @@ -55,13 +58,15 @@ import info.nightscout.utils.OKDialog; import info.nightscout.utils.PasswordProtection; import info.nightscout.utils.SP; -public class MainActivity extends AppCompatActivity implements View.OnClickListener { +public class MainActivity extends AppCompatActivity { private static Logger log = LoggerFactory.getLogger(MainActivity.class); - ImageButton menuButton; - protected PowerManager.WakeLock mWakeLock; + private ActionBarDrawerToggle actionBarDrawerToggle; + + private MenuItem pluginPreferencesMenuItem; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -71,16 +76,54 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe Iconify.with(new FontAwesomeModule()); LocaleHelper.onCreate(this, "en"); + setContentView(R.layout.activity_main); - menuButton = (ImageButton) findViewById(R.id.overview_menuButton); - menuButton.setOnClickListener(this); + setSupportActionBar(findViewById(R.id.toolbar)); + getSupportActionBar().setDisplayShowTitleEnabled(false); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setHomeButtonEnabled(true); + + DrawerLayout drawerLayout = findViewById(R.id.drawer_layout); + actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.open_navigation, R.string.close_navigation); + drawerLayout.addDrawerListener(actionBarDrawerToggle); + actionBarDrawerToggle.syncState(); onStatusEvent(new EventSetWakeLock(SP.getBoolean("lockscreen", false))); doMigrations(); registerBus(); - setUpTabs(false); + setupTabs(); + setupViews(false); + + final ViewPager viewPager = findViewById(R.id.pager); + viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + } + + @Override + public void onPageSelected(int position) { + checkPluginPreferences(viewPager); + } + + @Override + public void onPageScrollStateChanged(int state) { + } + }); + } + + private void checkPluginPreferences(ViewPager viewPager) { + if (pluginPreferencesMenuItem == null) return; + if (((TabPageAdapter) viewPager.getAdapter()).getPluginAt(viewPager.getCurrentItem()).getPreferencesId() != -1) + pluginPreferencesMenuItem.setEnabled(true); + else pluginPreferencesMenuItem.setEnabled(false); + } + + @Override + public void onPostCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { + super.onPostCreate(savedInstanceState, persistentState); + actionBarDrawerToggle.syncState(); } @Override @@ -127,39 +170,74 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe public void onStatusEvent(final EventRefreshGui ev) { String lang = SP.getString("language", "en"); LocaleHelper.setLocale(getApplicationContext(), lang); - runOnUiThread(new Runnable() { - @Override - public void run() { - if (ev.recreate) { - recreate(); - } else { - try { // activity may be destroyed - setUpTabs(true); - } catch (IllegalStateException e) { - log.error("Unhandled exception", e); - } + runOnUiThread(() -> { + if (ev.recreate) { + recreate(); + } else { + try { // activity may be destroyed + setupTabs(); + setupViews(true); + } catch (IllegalStateException e) { + log.error("Unhandled exception", e); } - - boolean lockScreen = BuildConfig.NSCLIENTOLNY && SP.getBoolean("lockscreen", false); - if (lockScreen) - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - else - getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } + + boolean lockScreen = BuildConfig.NSCLIENTOLNY && SP.getBoolean("lockscreen", false); + if (lockScreen) + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + else + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); }); } - private void setUpTabs(boolean switchToLast) { + private void setupViews(boolean switchToLast) { TabPageAdapter pageAdapter = new TabPageAdapter(getSupportFragmentManager(), this); + NavigationView navigationView = findViewById(R.id.navigation_view); + navigationView.setNavigationItemSelectedListener(menuItem -> { + return true; + }); + Menu menu = navigationView.getMenu(); + menu.clear(); for (PluginBase p : MainApp.getPluginsList()) { pageAdapter.registerNewFragment(p); + if (p.hasFragment() && !p.isFragmentVisible() && p.isEnabled(p.pluginDescription.getType())) { + MenuItem menuItem = menu.add(p.getName()); + menuItem.setCheckable(true); + menuItem.setOnMenuItemClickListener(item -> { + Intent intent = new Intent(this, SingleFragmentActivity.class); + intent.putExtra("plugin", MainApp.getPluginsList().indexOf(p)); + startActivity(intent); + return true; + }); + } } - ViewPager mPager = (ViewPager) findViewById(R.id.pager); + ViewPager mPager = findViewById(R.id.pager); mPager.setAdapter(pageAdapter); - SlidingTabLayout mTabs = (SlidingTabLayout) findViewById(R.id.tabs); - mTabs.setViewPager(mPager); if (switchToLast) mPager.setCurrentItem(pageAdapter.getCount() - 1, false); + checkPluginPreferences(mPager); + } + + private void setupTabs() { + ViewPager viewPager = findViewById(R.id.pager); + TabLayout normalTabs = findViewById(R.id.tabs_normal); + normalTabs.setupWithViewPager(viewPager, true); + TabLayout compactTabs = findViewById(R.id.tabs_compact); + compactTabs.setupWithViewPager(viewPager, true); + Toolbar toolbar = findViewById(R.id.toolbar); + if (SP.getBoolean("short_tabtitles", false)) { + normalTabs.setVisibility(View.GONE); + compactTabs.setVisibility(View.VISIBLE); + toolbar.setLayoutParams(new LinearLayout.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT, (int) getResources().getDimension(R.dimen.compact_height))); + } else { + normalTabs.setVisibility(View.VISIBLE); + compactTabs.setVisibility(View.GONE); + TypedValue typedValue = new TypedValue(); + if (getTheme().resolveAttribute(R.attr.actionBarSize, typedValue, true)) { + toolbar.setLayoutParams(new LinearLayout.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT, + TypedValue.complexToDimensionPixelSize(typedValue.data, getResources().getDisplayMetrics()))); + } + } } private void registerBus() { @@ -257,99 +335,96 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe } @Override - public void onClick(final View v) { - final Activity activity = this; - switch (v.getId()) { - case R.id.overview_menuButton: - PopupMenu popup = new PopupMenu(v.getContext(), v); - MenuInflater inflater = popup.getMenuInflater(); - inflater.inflate(R.menu.menu_main, popup.getMenu()); - popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - int id = item.getItemId(); - switch (id) { - case R.id.nav_preferences: - PasswordProtection.QueryPassword(v.getContext(), R.string.settings_password, "settings_password", new Runnable() { - @Override - public void run() { - Intent i = new Intent(v.getContext(), PreferencesActivity.class); - i.putExtra("id", -1); - startActivity(i); - } - }, null); - break; - case R.id.nav_historybrowser: - startActivity(new Intent(v.getContext(), HistoryBrowseActivity.class)); - break; - case R.id.nav_setupwizard: - startActivity(new Intent(v.getContext(), SetupWizardActivity.class)); - break; - case R.id.nav_resetdb: - new AlertDialog.Builder(v.getContext()) - .setTitle(R.string.nav_resetdb) - .setMessage(R.string.reset_db_confirm) - .setNegativeButton(android.R.string.cancel, null) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - MainApp.getDbHelper().resetDatabases(); - // should be handled by Plugin-Interface and - // additional service interface and plugin registry - FoodPlugin.getPlugin().getService().resetFood(); - TreatmentsPlugin.getPlugin().getService().resetTreatments(); - } - }) - .create() - .show(); - break; - case R.id.nav_export: - ImportExportPrefs.verifyStoragePermissions(activity); - ImportExportPrefs.exportSharedPreferences(activity); - break; - case R.id.nav_import: - ImportExportPrefs.verifyStoragePermissions(activity); - ImportExportPrefs.importSharedPreferences(activity); - break; - case R.id.nav_show_logcat: - LogDialog.showLogcat(v.getContext()); - break; - case R.id.nav_about: - AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext()); - builder.setTitle(MainApp.gs(R.string.app_name) + " " + BuildConfig.VERSION); - if (Config.NSCLIENT || Config.G5UPLOADER) - builder.setIcon(R.mipmap.yellowowl); - else - builder.setIcon(R.mipmap.blueowl); - String message = "Build: " + BuildConfig.BUILDVERSION + "\n"; - message += "Flavor: " + BuildConfig.FLAVOR + BuildConfig.BUILD_TYPE + "\n"; - message += MainApp.gs(R.string.configbuilder_nightscoutversion_label) + " " + ConfigBuilderPlugin.nightscoutVersionName; - if (MainApp.engineeringMode) - message += "\n" + MainApp.gs(R.string.engineering_mode_enabled); - message += MainApp.gs(R.string.about_link_urls); - final SpannableString messageSpanned = new SpannableString(message); - Linkify.addLinks(messageSpanned, Linkify.WEB_URLS); - builder.setMessage(messageSpanned); - builder.setPositiveButton(MainApp.gs(R.string.ok), null); - AlertDialog alertDialog = builder.create(); - alertDialog.show(); - ((TextView) alertDialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); - break; - case R.id.nav_exit: - log.debug("Exiting"); - MainApp.instance().stopKeepAliveService(); - MainApp.bus().post(new EventAppExit()); - MainApp.closeDbHelper(); - finish(); - System.runFinalization(); - System.exit(0); - break; - } - return false; - } - }); - popup.show(); - break; + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_main, menu); + pluginPreferencesMenuItem = menu.findItem(R.id.nav_plugin_preferences); + checkPluginPreferences(findViewById(R.id.pager)); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + switch (id) { + case R.id.nav_preferences: + PasswordProtection.QueryPassword(this, R.string.settings_password, "settings_password", () -> { + Intent i = new Intent(this, PreferencesActivity.class); + i.putExtra("id", -1); + startActivity(i); + }, null); + return true; + case R.id.nav_historybrowser: + startActivity(new Intent(this, HistoryBrowseActivity.class)); + return true; + case R.id.nav_setupwizard: + startActivity(new Intent(this, SetupWizardActivity.class)); + return true; + case R.id.nav_resetdb: + new AlertDialog.Builder(this) + .setTitle(R.string.nav_resetdb) + .setMessage(R.string.reset_db_confirm) + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(android.R.string.ok, (dialog, which) -> { + MainApp.getDbHelper().resetDatabases(); + // should be handled by Plugin-Interface and + // additional service interface and plugin registry + FoodPlugin.getPlugin().getService().resetFood(); + TreatmentsPlugin.getPlugin().getService().resetTreatments(); + }) + .create() + .show(); + return true; + case R.id.nav_export: + ImportExportPrefs.verifyStoragePermissions(this); + ImportExportPrefs.exportSharedPreferences(this); + return true; + case R.id.nav_import: + ImportExportPrefs.verifyStoragePermissions(this); + ImportExportPrefs.importSharedPreferences(this); + return true; + case R.id.nav_show_logcat: + LogDialog.showLogcat(this); + return true; + case R.id.nav_about: + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(MainApp.gs(R.string.app_name) + " " + BuildConfig.VERSION); + if (Config.NSCLIENT || Config.G5UPLOADER) + builder.setIcon(R.mipmap.yellowowl); + else + builder.setIcon(R.mipmap.blueowl); + String message = "Build: " + BuildConfig.BUILDVERSION + "\n"; + message += "Flavor: " + BuildConfig.FLAVOR + BuildConfig.BUILD_TYPE + "\n"; + message += MainApp.gs(R.string.configbuilder_nightscoutversion_label) + " " + ConfigBuilderPlugin.nightscoutVersionName; + if (MainApp.engineeringMode) + message += "\n" + MainApp.gs(R.string.engineering_mode_enabled); + message += MainApp.gs(R.string.about_link_urls); + final SpannableString messageSpanned = new SpannableString(message); + Linkify.addLinks(messageSpanned, Linkify.WEB_URLS); + builder.setMessage(messageSpanned); + builder.setPositiveButton(MainApp.gs(R.string.ok), null); + AlertDialog alertDialog = builder.create(); + alertDialog.show(); + ((TextView) alertDialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); + return true; + case R.id.nav_exit: + log.debug("Exiting"); + MainApp.instance().stopKeepAliveService(); + MainApp.bus().post(new EventAppExit()); + MainApp.closeDbHelper(); + finish(); + System.runFinalization(); + System.exit(0); + return true; + case R.id.nav_plugin_preferences: + ViewPager viewPager = findViewById(R.id.pager); + final PluginBase plugin = ((TabPageAdapter) viewPager.getAdapter()).getPluginAt(viewPager.getCurrentItem()); + PasswordProtection.QueryPassword(this, R.string.settings_password, "settings_password", () -> { + Intent i = new Intent(this, PreferencesActivity.class); + i.putExtra("id", plugin.getPreferencesId()); + startActivity(i); + }, null); + return true; } + return actionBarDrawerToggle.onOptionsItemSelected(item); } } diff --git a/app/src/main/java/info/nightscout/androidaps/SingleFragmentActivity.java b/app/src/main/java/info/nightscout/androidaps/SingleFragmentActivity.java new file mode 100644 index 0000000000..567799fe5e --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/SingleFragmentActivity.java @@ -0,0 +1,59 @@ +package info.nightscout.androidaps; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.view.ViewPager; +import android.support.v7.app.AppCompatActivity; +import android.view.Menu; +import android.view.MenuItem; + +import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.tabs.TabPageAdapter; +import info.nightscout.utils.PasswordProtection; + +public class SingleFragmentActivity extends AppCompatActivity { + + private PluginBase plugin; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_single_fragment); + + this.plugin = MainApp.getPluginsList().get(getIntent().getIntExtra("plugin", -1)); + setTitle(plugin.getName()); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayShowHomeEnabled(true); + + if (savedInstanceState == null) { + getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout, + Fragment.instantiate(this, plugin.pluginDescription.getFragmentClass())).commit(); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } + else if (item.getItemId() == R.id.nav_plugin_preferences) { + PasswordProtection.QueryPassword(this, R.string.settings_password, "settings_password", () -> { + Intent i = new Intent(this, PreferencesActivity.class); + i.putExtra("id", plugin.getPreferencesId()); + startActivity(i); + }, null); + return true; + } + return false; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + if (plugin.getPreferencesId() != -1) + getMenuInflater().inflate(R.menu.menu_single_fragment, menu); + return super.onCreateOptionsMenu(menu); + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/data/Profile.java b/app/src/main/java/info/nightscout/androidaps/data/Profile.java index 374612f2f5..844fa6472a 100644 --- a/app/src/main/java/info/nightscout/androidaps/data/Profile.java +++ b/app/src/main/java/info/nightscout/androidaps/data/Profile.java @@ -226,6 +226,10 @@ public class Profile { basal_v.setValueAt(i, description.basalMinimumRate); if (notify) sendBelowMinimumNotification(from); + } else if (basal_v.valueAt(i) > description.basalMaximumRate) { + basal_v.setValueAt(i, description.basalMaximumRate); + if (notify) + sendAboveMaximumNotification(from); } } } else { @@ -243,6 +247,10 @@ public class Profile { MainApp.bus().post(new EventNewNotification(new Notification(Notification.MINIMAL_BASAL_VALUE_REPLACED, String.format(MainApp.gs(R.string.minimalbasalvaluereplaced), from), Notification.NORMAL))); } + protected void sendAboveMaximumNotification(String from) { + MainApp.bus().post(new EventNewNotification(new Notification(Notification.MAXIMUM_BASAL_VALUE_REPLACED, String.format(MainApp.gs(R.string.maximumbasalvaluereplaced), from), Notification.NORMAL))); + } + private void validate(LongSparseArray array) { if (array.size() == 0) { isValid = false; diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.java b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.java index ec6976a2c7..2edf9033bf 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpDescription.java @@ -35,6 +35,7 @@ public class PumpDescription { public boolean isSetBasalProfileCapable = true; public double basalStep = 0.01d; public double basalMinimumRate = 0.04d; + public double basalMaximumRate = 25d; public boolean isRefillingCapable = false; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/CareportalFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/CareportalFragment.java index c5f1886265..264488f684 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/CareportalFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/CareportalFragment.java @@ -222,7 +222,7 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli double cageUrgent = nsSettings.getExtendedWarnValue("cage", "urgent", 72); double cageWarn = nsSettings.getExtendedWarnValue("cage", "warn", 48); - handleAge(sage, CareportalEvent.SITECHANGE, cageWarn, cageUrgent); + handleAge(cage, CareportalEvent.SITECHANGE, cageWarn, cageUrgent); double sageUrgent = nsSettings.getExtendedWarnValue("sage", "urgent", 166); double sageWarn = nsSettings.getExtendedWarnValue("sage", "warn", 164); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java index 35130c5209..04e7dcdbfd 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java @@ -87,9 +87,9 @@ public class ConfigBuilderPlugin extends PluginBase { super(new PluginDescription() .mainType(PluginType.GENERAL) .fragmentClass(ConfigBuilderFragment.class.getName()) - .showInList(false) + .showInList(true) .alwaysEnabled(true) - .alwayVisible(true) + .alwayVisible(false) .pluginName(R.string.configbuilder) .shortName(R.string.configbuilder_shortname) ); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/notifications/Notification.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/notifications/Notification.java index 9a374bf3f3..71b4842b8e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/notifications/Notification.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/notifications/Notification.java @@ -64,6 +64,7 @@ public class Notification { public static final int PERMISSION_LOCATION = 36; public static final int PERMISSION_BATTERY = 37; public static final int PERMISSION_SMS = 38; + public static final int MAXIMUM_BASAL_VALUE_REPLACED = 39; public int id; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/Cstatus.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/Cstatus.java deleted file mode 100644 index 53c0cf798f..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/Cstatus.java +++ /dev/null @@ -1,20 +0,0 @@ -package info.nightscout.androidaps.plugins.PumpInsight; - -/** - * Created by jamorham on 25/01/2018. - * - * Async command status - * - */ -enum Cstatus { - UNKNOWN, - PENDING, - SUCCESS, - FAILURE, - TIMEOUT; - - boolean success() { - return this == SUCCESS; - } - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/InsightAsyncAdapter.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/InsightAsyncAdapter.java deleted file mode 100644 index 3759a3f721..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/InsightAsyncAdapter.java +++ /dev/null @@ -1,95 +0,0 @@ -package info.nightscout.androidaps.plugins.PumpInsight; - -import android.os.PowerManager; - -import com.squareup.otto.Subscribe; - -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - -import info.nightscout.androidaps.MainApp; -import info.nightscout.androidaps.plugins.PumpInsight.events.EventInsightCallback; - -import static info.nightscout.androidaps.plugins.PumpInsight.utils.Helpers.getWakeLock; -import static info.nightscout.androidaps.plugins.PumpInsight.utils.Helpers.msSince; -import static info.nightscout.androidaps.plugins.PumpInsight.utils.Helpers.releaseWakeLock; -import static info.nightscout.androidaps.plugins.PumpInsight.utils.Helpers.tsl; - -/** - * Created by jamorham on 25/01/2018. - * - * Asynchronous adapter - * - */ - -public class InsightAsyncAdapter { - - private final ConcurrentHashMap commandResults = new ConcurrentHashMap<>(); - - InsightAsyncAdapter() { - MainApp.bus().register(this); - } - - // just log during debugging - private static void log(String msg) { - android.util.Log.e("INSIGHTPUMPASYNC", msg); - } - - @Subscribe - public void onStatusEvent(final EventInsightCallback ev) { - log("Received callback event: " + ev.toString()); - commandResults.put(ev.request_uuid, ev); - } - - // poll command result - private Cstatus checkCommandResult(UUID uuid) { - if (uuid == null) return Cstatus.FAILURE; - if (commandResults.containsKey(uuid)) { - if (commandResults.get(uuid).success) { - return Cstatus.SUCCESS; - } else { - return Cstatus.FAILURE; - } - } else { - return Cstatus.PENDING; - } - } - - // blocking call to wait for result callback - private Cstatus busyWaitForCommandInternal(final UUID uuid, long wait_time) { - final PowerManager.WakeLock wl = getWakeLock("insight-wait-cmd", 60000); - try { - log("busy wait for command " + uuid); - if (uuid == null) return Cstatus.FAILURE; - final long start_time = tsl(); - Cstatus status = checkCommandResult(uuid); - while ((status == Cstatus.PENDING) && msSince(start_time) < wait_time) { - //log("command result waiting"); - try { - Thread.sleep(200); - } catch (InterruptedException e) { - log("Got interrupted exception! " + e); - } - status = checkCommandResult(uuid); - } - if (status == Cstatus.PENDING) { - return Cstatus.TIMEOUT; - } else { - return status; - } - } finally { - releaseWakeLock(wl); - } - } - - // wait for and then package result, cleanup and return - Mstatus busyWaitForCommandResult(final UUID uuid, long wait_time) { - final Mstatus mstatus = new Mstatus(); - mstatus.cstatus = busyWaitForCommandInternal(uuid, wait_time); - mstatus.event = commandResults.get(uuid); - commandResults.remove(uuid); - return mstatus; - } - - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/InsightPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/InsightPlugin.java index 824a449f38..b99b8ec908 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/InsightPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/InsightPlugin.java @@ -9,7 +9,6 @@ import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.UUID; import info.nightscout.androidaps.BuildConfig; import info.nightscout.androidaps.Config; @@ -21,7 +20,6 @@ import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.TemporaryBasal; -import info.nightscout.androidaps.plugins.Treatments.Treatment; import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.ConstraintsInterface; import info.nightscout.androidaps.interfaces.PluginBase; @@ -33,7 +31,8 @@ import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotificati import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress; import info.nightscout.androidaps.plugins.Overview.notifications.Notification; -import info.nightscout.androidaps.plugins.PumpInsight.connector.CancelBolusTaskRunner; +import info.nightscout.androidaps.plugins.PumpInsight.connector.CancelBolusSilentlyTaskRunner; +import info.nightscout.androidaps.plugins.PumpInsight.connector.CancelTBRSilentlyTaskRunner; import info.nightscout.androidaps.plugins.PumpInsight.connector.Connector; import info.nightscout.androidaps.plugins.PumpInsight.connector.SetTBRTaskRunner; import info.nightscout.androidaps.plugins.PumpInsight.connector.StatusTaskRunner; @@ -44,12 +43,14 @@ import info.nightscout.androidaps.plugins.PumpInsight.history.HistoryReceiver; import info.nightscout.androidaps.plugins.PumpInsight.history.LiveHistory; import info.nightscout.androidaps.plugins.PumpInsight.utils.Helpers; import info.nightscout.androidaps.plugins.PumpInsight.utils.StatusItem; +import info.nightscout.androidaps.plugins.Treatments.Treatment; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.utils.DateUtil; import info.nightscout.utils.NSUpload; import info.nightscout.utils.SP; import sugar.free.sightparser.applayer.descriptors.ActiveBolus; import sugar.free.sightparser.applayer.descriptors.ActiveBolusType; +import sugar.free.sightparser.applayer.descriptors.MessagePriority; import sugar.free.sightparser.applayer.descriptors.PumpStatus; import sugar.free.sightparser.applayer.descriptors.configuration_blocks.BRProfileBlock; import sugar.free.sightparser.applayer.messages.AppLayerMessage; @@ -94,7 +95,6 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai private static boolean initialized = false; private static volatile boolean update_pending = false; private static Logger log = LoggerFactory.getLogger(InsightPlugin.class); - private final InsightAsyncAdapter async = new InsightAsyncAdapter(); private StatusTaskRunner.Result statusResult; private long statusResultTime = -1; private Date lastDataTime = new Date(0); @@ -115,10 +115,10 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai ); log("InsightPlugin instantiated"); pumpDescription.isBolusCapable = true; - pumpDescription.bolusStep = 0.05d; // specification says 0.05U up to 2U then 0.1U @ 2-5U 0.2U @ 10-20U 0.5U 10-20U (are these just UI restrictions?) + pumpDescription.bolusStep = 0.01d; // specification says 0.05U up to 2U then 0.1U @ 2-5U 0.2U @ 10-20U 0.5U 10-20U (are these just UI restrictions? Yes, they are!) pumpDescription.isExtendedBolusCapable = true; - pumpDescription.extendedBolusStep = 0.05d; // specification probably same as above + pumpDescription.extendedBolusStep = 0.01d; // specification probably same as above pumpDescription.extendedBolusDurationStep = 15; // 15 minutes up to 24 hours pumpDescription.extendedBolusMaxDuration = 24 * 60; @@ -138,6 +138,7 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai pumpDescription.is30minBasalRatesCapable = true; pumpDescription.basalStep = 0.01d; pumpDescription.basalMinimumRate = 0.02d; + pumpDescription.basalMaximumRate = 25d; pumpDescription.isRefillingCapable = true; @@ -191,7 +192,7 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai @Override public boolean isFakingTempsByExtendedBoluses() { - return false; + return true; } @Override @@ -287,17 +288,15 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai log("getPumpStatus"); if (Connector.get().isPumpConnected()) { log("is connected.. requesting status"); - final UUID uuid = aSyncTaskRunner(new StatusTaskRunner(connector.getServiceConnector()), "Status"); - Mstatus mstatus = async.busyWaitForCommandResult(uuid, BUSY_WAIT_TIME); - if (mstatus.success()) { + try { + setStatusResult(fetchTaskRunner(new StatusTaskRunner(connector.getServiceConnector()), StatusTaskRunner.Result.class)); log("GOT STATUS RESULT!!! PARTY WOOHOO!!!"); - setStatusResult((StatusTaskRunner.Result) mstatus.getResponseObject()); statusResultTime = Helpers.tsl(); processStatusResult(); updateGui(); connector.requestHistoryReSync(); connector.requestHistorySync(); - } else { + } catch (Exception e) { log("StatusTaskRunner wasn't successful."); if (connector.getServiceConnector().isConnectedToService() && connector.getServiceConnector().getStatus() != Status.CONNECTED) { if (Helpers.ratelimit("insight-reconnect", 2)) { @@ -313,6 +312,8 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai public void setStatusResult(StatusTaskRunner.Result result) { this.statusResult = result; + this.pumpDescription.basalMinimumRate = result.minimumBasalAmount; + this.pumpDescription.basalMaximumRate = result.maximumBasalAmount; } @Override @@ -335,9 +336,8 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai profileBlocks.add(new BRProfileBlock.ProfileBlock((((nextValue != null ? nextValue.timeAsSeconds : 24 * 60 * 60) - basalValue.timeAsSeconds) / 60), Helpers.roundDouble(basalValue.value, 2))); log("setNewBasalProfile: " + basalValue.value + " for " + Integer.toString(((nextValue != null ? nextValue.timeAsSeconds : 24 * 60 * 60) - basalValue.timeAsSeconds) / 60)); } - final UUID uuid = aSyncTaskRunner(new WriteBasalProfileTaskRunner(connector.getServiceConnector(), profileBlocks), "Write basal profile"); - final Mstatus ms = async.busyWaitForCommandResult(uuid, BUSY_WAIT_TIME); - if (ms.success()) { + try { + fetchTaskRunner(new WriteBasalProfileTaskRunner(connector.getServiceConnector(), profileBlocks)); MainApp.bus().post(new EventDismissNotification(Notification.FAILED_UDPATE_PROFILE)); Notification notification = new Notification(Notification.PROFILE_SET_OK, MainApp.gs(R.string.profile_set_ok), Notification.INFO, 60); MainApp.bus().post(new EventNewNotification(notification)); @@ -345,7 +345,7 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai result.enacted = true; result.comment = "OK"; this.profileBlocks = profileBlocks; - } else { + } catch (Exception e) { Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE, MainApp.gs(R.string.failedupdatebasalprofile), Notification.URGENT); MainApp.bus().post(new EventNewNotification(notification)); result.comment = MainApp.gs(R.string.failedupdatebasalprofile); @@ -403,17 +403,13 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai // is there an insulin component to the treatment? if (detailedBolusInfo.insulin > 0) { - final UUID cmd = deliverBolus(detailedBolusInfo.insulin); // actually request delivery - if (cmd == null) { + try { + bolusId = deliverBolus(detailedBolusInfo.insulin); + result.success = true; + detailedBolusInfo.pumpId = getRecordUniqueID(bolusId); + } catch (Exception e) { return pumpEnactFailure(); } - final Mstatus ms = async.busyWaitForCommandResult(cmd, BUSY_WAIT_TIME); - - result.success = ms.success(); - if (ms.success()) { - detailedBolusInfo.pumpId = getRecordUniqueID(ms.getResponseID()); - bolusId = ms.getResponseID(); - } } else { result.success = true; // always true with carb only treatments } @@ -440,20 +436,11 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai updateGui(); connector.tryToGetPumpStatusAgain(); - connector.requestHistorySync(30000); - if (result.success) while (true) { try { - Thread.sleep(200); - } catch (InterruptedException e) { - e.printStackTrace(); - break; - } - final UUID uuid = aSyncSingleCommand(new ActiveBolusesMessage(), "Active boluses"); - Mstatus mstatus = async.busyWaitForCommandResult(uuid, BUSY_WAIT_TIME); - if (mstatus.success()) { + Thread.sleep(500); final EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance(); - ActiveBolusesMessage activeBolusesMessage = (ActiveBolusesMessage) mstatus.getResponseObject(); + ActiveBolusesMessage activeBolusesMessage = fetchSingleMessage(new ActiveBolusesMessage(), ActiveBolusesMessage.class); ActiveBolus activeBolus = null; if (activeBolusesMessage.getBolus1() != null && activeBolusesMessage.getBolus1().getBolusID() == bolusingEvent.bolusId) activeBolus = activeBolusesMessage.getBolus1(); @@ -463,87 +450,60 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai activeBolus = activeBolusesMessage.getBolus3(); if (activeBolus == null) break; else { + int percentBefore = bolusingEvent.percent; bolusingEvent.percent = (int) (100D / activeBolus.getInitialAmount() * (activeBolus.getInitialAmount() - activeBolus.getLeftoverAmount())); bolusingEvent.status = String.format(MainApp.gs(R.string.bolusdelivering), activeBolus.getInitialAmount() - activeBolus.getLeftoverAmount()); - MainApp.bus().post(bolusingEvent); + if (percentBefore != bolusingEvent.percent) MainApp.bus().post(bolusingEvent); } - } else break; + } catch (Exception e) { + break; + } } + + connector.requestHistorySync(2000); return result; } @Override public void stopBolusDelivering() { CancelBolusMessage cancelBolusMessage = new CancelBolusMessage(); + cancelBolusMessage.setMessagePriority(MessagePriority.HIGHEST); cancelBolusMessage.setBolusId(EventOverviewBolusProgress.getInstance().bolusId); - final UUID cmd = aSyncSingleCommand(cancelBolusMessage, "Cancel standard bolus"); - - if (cmd == null) { - return; + try { + fetchSingleMessage(cancelBolusMessage); + } catch (Exception e) { } - - final Mstatus cs = async.busyWaitForCommandResult(cmd, BUSY_WAIT_TIME); - log("Got command status: " + cs); } // Temporary Basals @Override public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, boolean enforceNew) { - absoluteRate = Helpers.roundDouble(absoluteRate, 3); log("Set TBR absolute: " + absoluteRate); - final double base_basal = getBaseBasalRate(); - if (base_basal == 0) { + if (getBaseBasalRate() == 0) { log("Base basal rate appears to be zero!"); return pumpEnactFailure(); } - int percent_amount = (int) Math.round(100d / base_basal * absoluteRate); - log("Calculated requested rate: " + absoluteRate + " base rate: " + base_basal + " percentage: " + percent_amount + "%"); - percent_amount = (int) Math.round(((double) percent_amount) / 10d) * 10; - log("Calculated final rate: " + percent_amount + "%"); - - if (percent_amount == 100) { - return cancelTempBasal(false); - } - - if (percent_amount > 250) percent_amount = 250; - - - final SetTBRTaskRunner task = new SetTBRTaskRunner(connector.getServiceConnector(), percent_amount, durationInMinutes); - final UUID cmd = aSyncTaskRunner(task, "Set TBR abs: " + absoluteRate + " " + durationInMinutes + "m"); - - if (cmd == null) { + double percent = 100D / getBaseBasalRate() * absoluteRate; + log("Calculated requested rate: " + absoluteRate + " base rate: " + getBaseBasalRate() + " percentage: " + percent + "%"); + try { + if (percent > 250) { + log ("Calculated rate is above 250%, switching to emulation using extended boluses"); + cancelTempBasal(true); + if (!setExtendedBolus((absoluteRate - getBaseBasalRate()) / 60D * ((double) durationInMinutes), durationInMinutes).success) { + //Fallback to TBR if setting an extended bolus didn't work + log ("Setting an extended bolus didn't work, falling back to normal TBR"); + return setTempBasalPercent((int) percent, durationInMinutes, profile, true); + } + return new PumpEnactResult().success(true).enacted(true).absolute(absoluteRate).duration(durationInMinutes); + } else { + log ("Calculated rate is below or equal to 250%, using normal TBRs"); + cancelExtendedBolus(); + return setTempBasalPercent((int) percent, durationInMinutes, profile, true); + } + } catch (Exception e) { return pumpEnactFailure(); } - - Mstatus ms = async.busyWaitForCommandResult(cmd, BUSY_WAIT_TIME); - log("Got command status: " + ms); - - PumpEnactResult pumpEnactResult = new PumpEnactResult().enacted(true).isPercent(true).duration(durationInMinutes); - pumpEnactResult.percent = percent_amount; - pumpEnactResult.success = ms.success(); - pumpEnactResult.comment = ms.getCommandComment(); - - - if (pumpEnactResult.success) { - // create log entry - final TemporaryBasal tempBasal = new TemporaryBasal() - .date(System.currentTimeMillis()) - .percent(percent_amount) - .duration(durationInMinutes) - .source(Source.USER); - TreatmentsPlugin.getPlugin().addToHistoryTempBasal(tempBasal); - } - - if (Config.logPumpComm) - log.debug("Setting temp basal absolute: " + pumpEnactResult.success); - - updateGui(); - - connector.requestHistorySync(5000); - connector.tryToGetPumpStatusAgain(); - - return pumpEnactResult; } @@ -555,42 +515,24 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai if (percent == 100) { // This would cause a cancel if a tbr is in progress so treat as a cancel return cancelTempBasal(false); - } + } else if (percent > 250) percent = 250; - - final UUID cmd = aSyncTaskRunner(new SetTBRTaskRunner(connector.getServiceConnector(), percent, durationInMinutes), "Set TBR " + percent + "%" + " " + durationInMinutes + "m"); - - if (cmd == null) { - return pumpEnactFailure(); - } - - final Mstatus ms = async.busyWaitForCommandResult(cmd, BUSY_WAIT_TIME); - log("Got command status: " + ms); - - PumpEnactResult pumpEnactResult = new PumpEnactResult().enacted(true).isPercent(true).duration(durationInMinutes); - pumpEnactResult.percent = percent; - pumpEnactResult.success = ms.success(); - pumpEnactResult.comment = ms.getCommandComment(); - - if (pumpEnactResult.success) { - // create log entry + try { + fetchTaskRunner(new SetTBRTaskRunner(connector.getServiceConnector(), percent, durationInMinutes)); final TemporaryBasal tempBasal = new TemporaryBasal() .date(System.currentTimeMillis()) .percent(percent) .duration(durationInMinutes) - .source(Source.USER); // TODO check this is correct + .source(Source.USER); TreatmentsPlugin.getPlugin().addToHistoryTempBasal(tempBasal); + updateGui(); + if (Config.logPumpComm) log.debug("Set temp basal " + percent + "% for " + durationInMinutes + "m"); + connector.requestHistorySync(5000); + connector.tryToGetPumpStatusAgain(); + return new PumpEnactResult().success(true).enacted(true).percent(percent); + } catch (Exception e) { + return pumpEnactFailure(); } - - updateGui(); - - if (Config.logPumpComm) - log.debug("Set temp basal " + percent + "% for " + durationInMinutes + "m"); - - connector.requestHistorySync(5000); - connector.tryToGetPumpStatusAgain(); - - return pumpEnactResult; } @@ -598,35 +540,24 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai public PumpEnactResult cancelTempBasal(boolean enforceNew) { log("Cancel TBR"); - - fauxTBRcancel = !SP.getBoolean("insight_real_tbr_cancel", false); - - final UUID cmd; - - if (fauxTBRcancel) { - cmd = aSyncTaskRunner(new SetTBRTaskRunner(connector.getServiceConnector(), 100, 1), "Faux Cancel TBR - setting " + "90%" + " 1m"); - } else { - cmd = aSyncSingleCommand(new CancelTBRMessage(), "Cancel Temp Basal"); - } - if (cmd == null) { + try { + cancelExtendedBolus(); + realTBRCancel(); + updateGui(); + if (Config.logPumpComm) log.debug("Canceling temp basal"); + connector.requestHistorySync(5000); + connector.tryToGetPumpStatusAgain(); + return new PumpEnactResult().success(true).enacted(true).isTempCancel(true); + } catch (Exception e) { return pumpEnactFailure(); } + } - // TODO isn't conditional on one apparently being in progress only the history change - final Mstatus ms = async.busyWaitForCommandResult(cmd, BUSY_WAIT_TIME); - - if (TreatmentsPlugin.getPlugin().isTempBasalInProgress()) { + private void realTBRCancel() throws Exception { + if (fetchTaskRunner(new CancelTBRSilentlyTaskRunner(connector.getServiceConnector()), Boolean.class) && TreatmentsPlugin.getPlugin().isTempBasalInProgress()) { TemporaryBasal tempStop = new TemporaryBasal().date(System.currentTimeMillis()).source(Source.USER); TreatmentsPlugin.getPlugin().addToHistoryTempBasal(tempStop); } - updateGui(); - if (Config.logPumpComm) - log.debug("Canceling temp basal: "); // TODO get more info - - connector.requestHistorySync(5000); - connector.tryToGetPumpStatusAgain(); - - return new PumpEnactResult().success(ms.success()).enacted(true).isTempCancel(true); } @@ -635,88 +566,60 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai @Override public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) { log("Set Extended bolus " + insulin + " " + durationInMinutes); - ExtendedBolusMessage extendedBolusMessage = new ExtendedBolusMessage(); - extendedBolusMessage.setAmount(insulin); - extendedBolusMessage.setDuration(durationInMinutes); - final UUID cmd = aSyncSingleCommand(extendedBolusMessage, "Extended bolus U" + insulin + " mins:" + durationInMinutes); - if (cmd == null) { - return pumpEnactFailure(); - } - - final Mstatus ms = async.busyWaitForCommandResult(cmd, BUSY_WAIT_TIME); - log("Got command status: " + ms); - - PumpEnactResult pumpEnactResult = new PumpEnactResult().enacted(true).bolusDelivered(insulin).duration(durationInMinutes); - pumpEnactResult.success = ms.success(); - pumpEnactResult.comment = ms.getCommandComment(); - - if (pumpEnactResult.success) { - // create log entry + try { + ExtendedBolusMessage extendedBolusMessage = new ExtendedBolusMessage(); + extendedBolusMessage.setAmount(insulin); + extendedBolusMessage.setDuration(durationInMinutes); + BolusMessage bolusMessage = fetchSingleMessage(extendedBolusMessage, BolusMessage.class); final ExtendedBolus extendedBolus = new ExtendedBolus(); extendedBolus.date = System.currentTimeMillis(); extendedBolus.insulin = insulin; extendedBolus.durationInMinutes = durationInMinutes; extendedBolus.source = Source.USER; - extendedBolus.pumpId = getRecordUniqueID(ms.getResponseID()); + extendedBolus.pumpId = getRecordUniqueID(bolusMessage.getBolusId()); TreatmentsPlugin.getPlugin().addToHistoryExtendedBolus(extendedBolus); + updateGui(); + connector.requestHistorySync(30000); + connector.tryToGetPumpStatusAgain(); + if (Config.logPumpComm) + log.debug("Setting extended bolus: " + insulin + " mins:" + durationInMinutes); + return new PumpEnactResult().success(true).enacted(true).duration(durationInMinutes).bolusDelivered(insulin); + } catch (Exception e) { + return pumpEnactFailure(); } - - if (Config.logPumpComm) - log.debug("Setting extended bolus: " + insulin + " mins:" + durationInMinutes + " " + pumpEnactResult.comment); - - updateGui(); - - connector.requestHistorySync(30000); - connector.tryToGetPumpStatusAgain(); - - return pumpEnactResult; } @Override public PumpEnactResult cancelExtendedBolus() { - log("Cancel Extended bolus"); - // TODO note always sends cancel to pump but only changes history if present + Integer bolusId = null; - final UUID cmd = aSyncTaskRunner(new CancelBolusTaskRunner(connector.getServiceConnector(), ActiveBolusType.EXTENDED), "Cancel extended bolus"); - - if (cmd == null) { + try { + bolusId = fetchTaskRunner(new CancelBolusSilentlyTaskRunner(connector.getServiceConnector(), ActiveBolusType.EXTENDED), Integer.class); + if (TreatmentsPlugin.getPlugin().isInHistoryExtendedBoluslInProgress()) { + ExtendedBolus exStop = new ExtendedBolus(System.currentTimeMillis()); + exStop.source = Source.USER; + TreatmentsPlugin.getPlugin().addToHistoryExtendedBolus(exStop); + } + if (Config.logPumpComm) log.debug("Cancel extended bolus:"); + if (bolusId != null) connector.requestHistorySync(5000); + connector.tryToGetPumpStatusAgain(); + updateGui(); + return new PumpEnactResult().success(true).enacted(bolusId != null); + } catch (Exception e) { return pumpEnactFailure(); } - - final Mstatus ms = async.busyWaitForCommandResult(cmd, BUSY_WAIT_TIME); - - if (TreatmentsPlugin.getPlugin().isInHistoryExtendedBoluslInProgress()) { - ExtendedBolus exStop = new ExtendedBolus(System.currentTimeMillis()); - exStop.source = Source.USER; - TreatmentsPlugin.getPlugin().addToHistoryExtendedBolus(exStop); - } - - if (Config.logPumpComm) - log.debug("Cancel extended bolus:"); - - updateGui(); - - connector.requestHistorySync(5000); - connector.tryToGetPumpStatusAgain(); - - return new PumpEnactResult().success(ms.success()).enacted(true); } - private synchronized UUID deliverBolus(double bolusValue) { + private int deliverBolus(double bolusValue) throws Exception { log("DeliverBolus: " + bolusValue); - if (bolusValue == 0) return null; - if (bolusValue < 0) return null; - - // TODO check limits here or they already occur via a previous constraint interface? - final StandardBolusMessage message = new StandardBolusMessage(); message.setAmount(bolusValue); - return aSyncSingleCommand(message, "Deliver Bolus " + bolusValue); + return fetchSingleMessage(message, BolusMessage.class).getBolusId(); } @Override @@ -931,82 +834,34 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai } } - // Utility - - private synchronized UUID aSyncSingleCommand(final AppLayerMessage msg, final String name) { - // if (!isConnected()) return false; - //if (isBusy()) return false; - log("asyncSinglecommand called: " + name); - final EventInsightCallback event = new EventInsightCallback(); - new Thread() { - @Override - public void run() { - log("asyncSingleCommand thread"); - final SingleMessageTaskRunner singleMessageTaskRunner = new SingleMessageTaskRunner(connector.getServiceConnector(), msg); - try { - singleMessageTaskRunner.fetch(new TaskRunner.ResultCallback() { - @Override - public void onResult(Object o) { - lastDataTime = new Date(); - log(name + " success"); - event.response_object = o; - if (o instanceof BolusMessage) { - event.response_id = ((BolusMessage) o).getBolusId(); - } - event.success = true; - pushCallbackEvent(event); - } - - @Override - public void onError(Exception e) { - log(name + " error"); - event.message = e.getMessage(); - pushCallbackEvent(event); - } - }); - - } catch (Exception e) { - log("EXCEPTION" + e.toString()); - } - } - }.start(); - return event.request_uuid; + private void fetchTaskRunner(TaskRunner taskRunner) throws Exception { + fetchTaskRunner(taskRunner, Object.class); } - private synchronized UUID aSyncTaskRunner(final TaskRunner task, final String name) { - // if (!isConnected()) return false; - //if (isBusy()) return false; - log("asyncTaskRunner called: " + name); - final EventInsightCallback event = new EventInsightCallback(); - new Thread() { - @Override - public void run() { - log("asyncTaskRunner thread"); - try { - task.fetch(new TaskRunner.ResultCallback() { - @Override - public void onResult(Object o) { - lastDataTime = new Date(); - log(name + " success"); - event.response_object = o; - event.success = true; - pushCallbackEvent(event); - } + private void fetchSingleMessage(AppLayerMessage message) throws Exception { + fetchSingleMessage(message, AppLayerMessage.class); + } - @Override - public void onError(Exception e) { - log(name + " error"); - event.message = e.getMessage(); - pushCallbackEvent(event); - } - }); + private T fetchTaskRunner(TaskRunner taskRunner, Class resultType) throws Exception { + try { + T result = (T) taskRunner.fetchAndWaitUsingLatch(BUSY_WAIT_TIME); + lastDataTime = new Date(); + return result; + } catch (Exception e) { + log("Error while fetching " + taskRunner.getClass().getSimpleName() + ": " + e.getClass().getSimpleName()); + throw e; + } + } - } catch (Exception e) { - log("EXCEPTION" + e.toString()); - } - } - }.start(); - return event.request_uuid; + private T fetchSingleMessage(AppLayerMessage message, Class resultType) throws Exception { + try { + T result = (T) new SingleMessageTaskRunner(connector.getServiceConnector(), message).fetchAndWaitUsingLatch(BUSY_WAIT_TIME); + lastDataTime = new Date(); + return result; + } catch (Exception e) { + log("Error while fetching " + message.getClass().getSimpleName() + ": " + e.getClass().getSimpleName()); + throw e; + } } @@ -1016,14 +871,6 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai // Constraints - @Override - public Constraint applyBasalConstraints(Constraint absoluteRate, Profile profile) { - if (statusResult != null) { - absoluteRate.setIfSmaller(statusResult.maximumBasalAmount, String.format(MainApp.gs(R.string.limitingbasalratio), statusResult.maximumBasalAmount, MainApp.gs(R.string.pumplimit)), this); - } - return absoluteRate; - } - @Override public Constraint applyBasalPercentConstraints(Constraint percentRate, Profile profile) { percentRate.setIfGreater(0, String.format(MainApp.gs(R.string.limitingpercentrate), 0, MainApp.gs(R.string.itmustbepositivevalue)), this); @@ -1034,8 +881,10 @@ public class InsightPlugin extends PluginBase implements PumpInterface, Constrai @Override public Constraint applyBolusConstraints(Constraint insulin) { - if (statusResult != null) + if (statusResult != null) { insulin.setIfSmaller(statusResult.maximumBolusAmount, String.format(MainApp.gs(R.string.limitingbolus), statusResult.maximumBolusAmount, MainApp.gs(R.string.pumplimit)), this); + insulin.setIfGreater(statusResult.minimumBolusAmount, String.format(MainApp.gs(R.string.limitingbolus), statusResult.maximumBolusAmount, MainApp.gs(R.string.pumplimit)), this); + } return insulin; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/Mstatus.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/Mstatus.java deleted file mode 100644 index 8797325f7c..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/Mstatus.java +++ /dev/null @@ -1,50 +0,0 @@ -package info.nightscout.androidaps.plugins.PumpInsight; - -import info.nightscout.androidaps.plugins.PumpInsight.events.EventInsightCallback; - -/** - * Created by jamorham on 01/02/2018. - * - * Encapsulates results from commands - */ - -class Mstatus { - - Cstatus cstatus = Cstatus.UNKNOWN; - EventInsightCallback event; - - // comment field preparation for results - String getCommandComment() { - if (success()) { - return "OK"; - } else { - return (event == null) ? "EVENT DATA IS NULL - ERROR OR FIREWALL ENABLED?" : event.message; - } - } - - boolean success() { - return cstatus.success(); - } - - int getResponseID() { - if (success()) { - return event.response_id; - } else { - return -2; // invalid - } - } - - Object getResponseObject() { - if (success()) { - return event.response_object; - } else { - return null; - } - } - - @Override - public String toString() { - return cstatus + " " + event; - } - -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/CancelBolusSilentlyTaskRunner.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/CancelBolusSilentlyTaskRunner.java new file mode 100644 index 0000000000..7b3108602e --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/CancelBolusSilentlyTaskRunner.java @@ -0,0 +1,66 @@ +package info.nightscout.androidaps.plugins.PumpInsight.connector; + +import sugar.free.sightparser.applayer.descriptors.ActiveBolusType; +import sugar.free.sightparser.applayer.descriptors.MessagePriority; +import sugar.free.sightparser.applayer.descriptors.alerts.Warning38BolusCancelled; +import sugar.free.sightparser.applayer.messages.AppLayerMessage; +import sugar.free.sightparser.applayer.messages.remote_control.CancelBolusMessage; +import sugar.free.sightparser.applayer.messages.remote_control.DismissAlertMessage; +import sugar.free.sightparser.applayer.messages.status.ActiveAlertMessage; +import sugar.free.sightparser.applayer.messages.status.ActiveBolusesMessage; +import sugar.free.sightparser.handling.SightServiceConnector; +import sugar.free.sightparser.handling.TaskRunner; + +// by Tebbe Ubben + +public class CancelBolusSilentlyTaskRunner extends TaskRunner { + + private ActiveBolusType bolusType; + private long cancelledAt; + private int bolusId; + + public CancelBolusSilentlyTaskRunner(SightServiceConnector serviceConnector, ActiveBolusType bolusType) { + super(serviceConnector); + this.bolusType = bolusType; + } + + @Override + protected AppLayerMessage run(AppLayerMessage message) throws Exception { + if (message == null) return new ActiveBolusesMessage(); + else if (message instanceof ActiveBolusesMessage) { + ActiveBolusesMessage bolusesMessage = (ActiveBolusesMessage) message; + CancelBolusMessage cancelBolusMessage = new CancelBolusMessage(); + if (bolusesMessage.getBolus1().getBolusType() == bolusType) + bolusId = bolusesMessage.getBolus1().getBolusID(); + else if (bolusesMessage.getBolus2().getBolusType() == bolusType) + bolusId = bolusesMessage.getBolus2().getBolusID(); + else if (bolusesMessage.getBolus3().getBolusType() == bolusType) + bolusId = bolusesMessage.getBolus3().getBolusID(); + else finish(null); + cancelBolusMessage.setBolusId(bolusId); + return cancelBolusMessage; + } else if (message instanceof CancelBolusMessage) { + cancelledAt = System.currentTimeMillis(); + ActiveAlertMessage activeAlertMessage = new ActiveAlertMessage(); + activeAlertMessage.setMessagePriority(MessagePriority.HIGHER); + return activeAlertMessage; + } else if (message instanceof ActiveAlertMessage) { + ActiveAlertMessage activeAlertMessage = (ActiveAlertMessage) message; + if (activeAlertMessage.getAlert() == null) { + if (System.currentTimeMillis() - cancelledAt >= 10000) finish(bolusId); + else { + ActiveAlertMessage activeAlertMessage2 = new ActiveAlertMessage(); + activeAlertMessage2.setMessagePriority(MessagePriority.HIGHER); + return activeAlertMessage2; + } + } else if (!(activeAlertMessage.getAlert() instanceof Warning38BolusCancelled)) finish(bolusId); + else { + DismissAlertMessage dismissAlertMessage = new DismissAlertMessage(); + dismissAlertMessage.setAlertID(activeAlertMessage.getAlertID()); + dismissAlertMessage.setMessagePriority(MessagePriority.HIGHER); + return dismissAlertMessage; + } + } else if (message instanceof DismissAlertMessage) finish(bolusId); + return null; + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/CancelBolusTaskRunner.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/CancelBolusTaskRunner.java deleted file mode 100644 index f350b80851..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/CancelBolusTaskRunner.java +++ /dev/null @@ -1,38 +0,0 @@ -package info.nightscout.androidaps.plugins.PumpInsight.connector; - -import sugar.free.sightparser.applayer.messages.AppLayerMessage; -import sugar.free.sightparser.applayer.descriptors.ActiveBolusType; -import sugar.free.sightparser.applayer.messages.remote_control.CancelBolusMessage; -import sugar.free.sightparser.applayer.messages.status.ActiveBolusesMessage; -import sugar.free.sightparser.handling.SightServiceConnector; -import sugar.free.sightparser.handling.TaskRunner; - -// by Tebbe Ubben - -public class CancelBolusTaskRunner extends TaskRunner { - - private ActiveBolusType bolusType; - - public CancelBolusTaskRunner(SightServiceConnector serviceConnector, ActiveBolusType bolusType) { - super(serviceConnector); - this.bolusType = bolusType; - } - - @Override - protected AppLayerMessage run(AppLayerMessage message) throws Exception { - if (message == null) return new ActiveBolusesMessage(); - else if (message instanceof ActiveBolusesMessage) { - ActiveBolusesMessage bolusesMessage = (ActiveBolusesMessage) message; - CancelBolusMessage cancelBolusMessage = new CancelBolusMessage(); - if (bolusesMessage.getBolus1().getBolusType() == bolusType) - cancelBolusMessage.setBolusId(bolusesMessage.getBolus1().getBolusID()); - else if (bolusesMessage.getBolus2().getBolusType() == bolusType) - cancelBolusMessage.setBolusId(bolusesMessage.getBolus2().getBolusID()); - else if (bolusesMessage.getBolus3().getBolusType() == bolusType) - cancelBolusMessage.setBolusId(bolusesMessage.getBolus3().getBolusID()); - else finish(null); - return cancelBolusMessage; - } else if (message instanceof CancelBolusMessage) finish(null); - return null; - } -} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/CancelTBRSilentlyTaskRunner.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/CancelTBRSilentlyTaskRunner.java new file mode 100644 index 0000000000..9a3068aef9 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/CancelTBRSilentlyTaskRunner.java @@ -0,0 +1,50 @@ +package info.nightscout.androidaps.plugins.PumpInsight.connector; + +import sugar.free.sightparser.applayer.descriptors.MessagePriority; +import sugar.free.sightparser.applayer.descriptors.alerts.Warning36TBRCancelled; +import sugar.free.sightparser.applayer.messages.AppLayerMessage; +import sugar.free.sightparser.applayer.messages.remote_control.CancelTBRMessage; +import sugar.free.sightparser.applayer.messages.remote_control.DismissAlertMessage; +import sugar.free.sightparser.applayer.messages.status.ActiveAlertMessage; +import sugar.free.sightparser.applayer.messages.status.CurrentTBRMessage; +import sugar.free.sightparser.handling.SightServiceConnector; +import sugar.free.sightparser.handling.TaskRunner; + +public class CancelTBRSilentlyTaskRunner extends TaskRunner { + + private long cancelledAt; + + public CancelTBRSilentlyTaskRunner(SightServiceConnector serviceConnector) { + super(serviceConnector); + } + + @Override + protected AppLayerMessage run(AppLayerMessage message) throws Exception { + if (message == null) return new CurrentTBRMessage(); + else if (message instanceof CurrentTBRMessage) { + if (((CurrentTBRMessage) message).getPercentage() == 100) finish(false); + else return new CancelTBRMessage(); + } else if (message instanceof CancelTBRMessage) { + ActiveAlertMessage activeAlertMessage = new ActiveAlertMessage(); + activeAlertMessage.setMessagePriority(MessagePriority.HIGHER); + return activeAlertMessage; + } else if (message instanceof ActiveAlertMessage) { + ActiveAlertMessage activeAlertMessage = (ActiveAlertMessage) message; + if (activeAlertMessage.getAlert() == null) { + if (System.currentTimeMillis() - cancelledAt >= 10000) finish(true); + else { + ActiveAlertMessage activeAlertMessage2 = new ActiveAlertMessage(); + activeAlertMessage2.setMessagePriority(MessagePriority.HIGHER); + return activeAlertMessage2; + } + } else if (!(activeAlertMessage.getAlert() instanceof Warning36TBRCancelled)) finish(true); + else { + DismissAlertMessage dismissAlertMessage = new DismissAlertMessage(); + dismissAlertMessage.setAlertID(activeAlertMessage.getAlertID()); + dismissAlertMessage.setMessagePriority(MessagePriority.HIGHER); + return dismissAlertMessage; + } + } else if (message instanceof DismissAlertMessage) finish(true); + return null; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/SetTBRTaskRunner.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/SetTBRTaskRunner.java index 1506ecb4a9..f18bb0d487 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/SetTBRTaskRunner.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/SetTBRTaskRunner.java @@ -25,25 +25,15 @@ public class SetTBRTaskRunner extends TaskRunner { if (message == null) return new CurrentTBRMessage(); else if (message instanceof CurrentTBRMessage) { if (((CurrentTBRMessage) message).getPercentage() == 100) { - if (amount == 100) finish(amount); - else { - SetTBRMessage setTBRMessage = new SetTBRMessage(); - setTBRMessage.setDuration(duration); - setTBRMessage.setAmount(amount); - return setTBRMessage; - } + SetTBRMessage setTBRMessage = new SetTBRMessage(); + setTBRMessage.setDuration(duration); + setTBRMessage.setAmount(amount); + return setTBRMessage; } else { - if (amount == 100) { - ChangeTBRMessage changeTBRMessage = new ChangeTBRMessage(); - changeTBRMessage.setDuration(1); - changeTBRMessage.setAmount(90); - return changeTBRMessage; - } else { - ChangeTBRMessage changeTBRMessage = new ChangeTBRMessage(); - changeTBRMessage.setDuration(duration); - changeTBRMessage.setAmount(amount); - return changeTBRMessage; - } + ChangeTBRMessage changeTBRMessage = new ChangeTBRMessage(); + changeTBRMessage.setDuration(duration); + changeTBRMessage.setAmount(amount); + return changeTBRMessage; } } else if (message instanceof SetTBRMessage) finish(amount); return null; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/StatusTaskRunner.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/StatusTaskRunner.java index 86e01f98f8..1df56be468 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/StatusTaskRunner.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/connector/StatusTaskRunner.java @@ -12,6 +12,8 @@ import sugar.free.sightparser.applayer.descriptors.configuration_blocks.BRProfil import sugar.free.sightparser.applayer.descriptors.configuration_blocks.BRProfile5Block; import sugar.free.sightparser.applayer.descriptors.configuration_blocks.BRProfileBlock; import sugar.free.sightparser.applayer.descriptors.configuration_blocks.ConfigurationBlock; +import sugar.free.sightparser.applayer.descriptors.configuration_blocks.FactoryMinBRAmountBlock; +import sugar.free.sightparser.applayer.descriptors.configuration_blocks.FactoryMinBolusAmountBlock; import sugar.free.sightparser.applayer.descriptors.configuration_blocks.MaxBRAmountBlock; import sugar.free.sightparser.applayer.descriptors.configuration_blocks.MaxBolusAmountBlock; import sugar.free.sightparser.applayer.messages.AppLayerMessage; @@ -102,6 +104,16 @@ public class StatusTaskRunner extends TaskRunner { return readMessage; } else if (configurationBlock instanceof MaxBRAmountBlock) { result.maximumBasalAmount = ((MaxBRAmountBlock) configurationBlock).getMaximumAmount(); + ReadConfigurationBlockMessage readMessage = new ReadConfigurationBlockMessage(); + readMessage.setConfigurationBlockID(FactoryMinBRAmountBlock.ID); + return readMessage; + } else if (configurationBlock instanceof FactoryMinBRAmountBlock) { + result.minimumBasalAmount = ((FactoryMinBRAmountBlock) configurationBlock).getMinimumAmount(); + ReadConfigurationBlockMessage readMessage = new ReadConfigurationBlockMessage(); + readMessage.setConfigurationBlockID(FactoryMinBolusAmountBlock.ID); + return readMessage; + } else if (configurationBlock instanceof FactoryMinBolusAmountBlock) { + result.minimumBolusAmount = ((FactoryMinBolusAmountBlock) configurationBlock).getMinimumAmount(); finish(result); } } @@ -122,5 +134,7 @@ public class StatusTaskRunner extends TaskRunner { public List basalProfile; public double maximumBolusAmount; public double maximumBasalAmount; + public double minimumBolusAmount; + public double minimumBasalAmount; } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/history/HistoryIntentAdapter.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/history/HistoryIntentAdapter.java index e7784287b7..2c2235bf47 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/history/HistoryIntentAdapter.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpInsight/history/HistoryIntentAdapter.java @@ -58,13 +58,8 @@ class HistoryIntentAdapter { final long record_unique_id = getRecordUniqueID(pump_serial_number, pump_record_id); - // other sanity checks - if ((pump_tbr_percent == 90) && (pump_tbr_duration <= 1)) { - log("Not creating TBR record for faux cancel"); - } else { - log("Creating TBR record: " + pump_tbr_percent + "% " + pump_tbr_duration + "m" + " id:" + record_unique_id); - logAdapter.createTBRrecord(start_time, pump_tbr_percent, pump_tbr_duration, record_unique_id); - } + log("Creating TBR record: " + pump_tbr_percent + "% " + pump_tbr_duration + "m" + " id:" + record_unique_id); + logAdapter.createTBRrecord(start_time, pump_tbr_percent, pump_tbr_duration, record_unique_id); } void processDeliveredBolusIntent(Intent intent) { @@ -160,8 +155,10 @@ class HistoryIntentAdapter { if (SP.getBoolean("insight_automatic_careportal_events", false)) { Date date = getDateExtra(intent, HistoryBroadcast.EXTRA_EVENT_TIME); String alertType = intent.getStringExtra(HistoryBroadcast.EXTRA_ALERT_TYPE); + int alertText = getAlertText(alertType); + if (alertText == 0) return; if (MainApp.getDbHelper().getCareportalEventFromTimestamp(date.getTime()) != null) return; - logNote(date, MainApp.gs(getAlertText(alertType))); + logNote(date, MainApp.gs(alertText)); } } @@ -231,8 +228,8 @@ class HistoryIntentAdapter { if (type.equals("Warning32BatteryLow")) return R.string.alert_w32; if (type.equals("Warning33InvalidDateTime")) return R.string.alert_w33; if (type.equals("Warning34EndOfWarranty")) return R.string.alert_w34; - if (type.equals("Warning36TBRCancelled")) return R.string.alert_w36; - if (type.equals("Warning38BolusCancelled")) return R.string.alert_w38; + if (type.equals("Warning36TBRCancelled")) return 0; + if (type.equals("Warning38BolusCancelled")) return 0; if (type.equals("Warning39LoantimeWarning")) return R.string.alert_w39; return 0; } diff --git a/app/src/main/java/info/nightscout/androidaps/tabs/SlidingTabLayout.java b/app/src/main/java/info/nightscout/androidaps/tabs/SlidingTabLayout.java deleted file mode 100644 index 80424a04f7..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/tabs/SlidingTabLayout.java +++ /dev/null @@ -1,322 +0,0 @@ -package info.nightscout.androidaps.tabs;/* - * Copyright 2014 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import android.content.Context; -import android.graphics.Typeface; -import android.support.v4.view.PagerAdapter; -import android.support.v4.view.ViewPager; -import android.util.AttributeSet; -import android.util.SparseArray; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.HorizontalScrollView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import info.nightscout.androidaps.R; - -/** - * To be used with ViewPager to provide a tab indicator component which give constant feedback as to - * the user's scroll progress. - *

- * To use the component, simply add it to your view hierarchy. Then in your - * {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call - * {@link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for. - *

- * The colors can be customized in two ways. The first and simplest is to provide an array of colors - * via {@link #setSelectedIndicatorColors(int...)}. The - * alternative is via the {@link TabColorizer} interface which provides you complete control over - * which color is used for any individual position. - *

- * The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)}, - * providing the layout ID of your custom layout. - */ -public class SlidingTabLayout extends HorizontalScrollView { - /** - * Allows complete control over the colors drawn in the tab layout. Set with - * {@link #setCustomTabColorizer(TabColorizer)}. - */ - public interface TabColorizer { - - /** - * @return return the color of the indicator used when {@code position} is selected. - */ - int getIndicatorColor(int position); - - } - - private static final int TITLE_OFFSET_DIPS = 24; - private static final int TAB_VIEW_PADDING_DIPS = 9; - private static final int TAB_VIEW_TEXT_SIZE_SP = 12; - - private int mTitleOffset; - - private int mTabViewLayoutId; - private int mTabViewTextViewId; - private boolean mDistributeEvenly; - - private ViewPager mViewPager; - private SparseArray mContentDescriptions = new SparseArray(); - private ViewPager.OnPageChangeListener mViewPagerPageChangeListener; - - private final SlidingTabStrip mTabStrip; - - public SlidingTabLayout(Context context) { - this(context, null); - } - - public SlidingTabLayout(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - // Disable the Scroll Bar - setHorizontalScrollBarEnabled(false); - // Make sure that the Tab Strips fills this View - setFillViewport(true); - - mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density); - - mTabStrip = new SlidingTabStrip(context); - addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); - setBackgroundColor(context.getResources().getColor(R.color.tabBgColor)); - } - - /** - * Set the custom {@link TabColorizer} to be used. - * - * If you only require simple custmisation then you can use - * {@link #setSelectedIndicatorColors(int...)} to achieve - * similar effects. - */ - public void setCustomTabColorizer(TabColorizer tabColorizer) { - mTabStrip.setCustomTabColorizer(tabColorizer); - } - - public void setDistributeEvenly(boolean distributeEvenly) { - mDistributeEvenly = distributeEvenly; - } - - /** - * Sets the colors to be used for indicating the selected tab. These colors are treated as a - * circular array. Providing one color will mean that all tabs are indicated with the same color. - */ - public void setSelectedIndicatorColors(int... colors) { - mTabStrip.setSelectedIndicatorColors(colors); - } - - /** - * Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are - * required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so - * that the layout can update it's scroll position correctly. - * - * @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener) - */ - public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { - mViewPagerPageChangeListener = listener; - } - - /** - * Set the custom layout to be inflated for the tab views. - * - * @param layoutResId Layout id to be inflated - * @param textViewId id of the {@link TextView} in the inflated view - */ - public void setCustomTabView(int layoutResId, int textViewId) { - mTabViewLayoutId = layoutResId; - mTabViewTextViewId = textViewId; - } - - /** - * Sets the associated view pager. Note that the assumption here is that the pager content - * (number of tabs and tab titles) does not change after this call has been made. - */ - public void setViewPager(ViewPager viewPager) { - mTabStrip.removeAllViews(); - - mViewPager = viewPager; - if (viewPager != null) { - viewPager.setOnPageChangeListener(new InternalViewPagerListener()); - populateTabStrip(); - } - } - - /** - * Create a default view to be used for tabs. This is called if a custom tab view is not set via - * {@link #setCustomTabView(int, int)}. - */ - protected TextView createDefaultTabView(Context context) { - TextView textView = new TextView(context); - textView.setGravity(Gravity.CENTER); - textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP); - textView.setTypeface(Typeface.DEFAULT_BOLD); - textView.setLayoutParams(new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - - TypedValue outValue = new TypedValue(); - getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, - outValue, true); - textView.setBackgroundResource(outValue.resourceId); - textView.setAllCaps(true); - - int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density); - textView.setPadding(padding, padding, padding, padding); - - return textView; - } - - private void populateTabStrip() { - final PagerAdapter adapter = mViewPager.getAdapter(); - final View.OnClickListener tabClickListener = new TabClickListener(); - - for (int i = 0; i < adapter.getCount(); i++) { - View tabView = null; - TextView tabTitleView = null; - - if (mTabViewLayoutId != 0) { - // If there is a custom tab view layout id set, try and inflate it - tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip, - false); - tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId); - } - - if (tabView == null) { - tabView = createDefaultTabView(getContext()); - } - - if (tabTitleView == null && TextView.class.isInstance(tabView)) { - tabTitleView = (TextView) tabView; - } - - if (mDistributeEvenly) { - LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) tabView.getLayoutParams(); - lp.width = 0; - lp.weight = 1; - } - - tabTitleView.setText(adapter.getPageTitle(i)); - tabView.setOnClickListener(tabClickListener); - String desc = mContentDescriptions.get(i, null); - if (desc != null) { - tabView.setContentDescription(desc); - } - - mTabStrip.addView(tabView); - if (i == mViewPager.getCurrentItem()) { - tabView.setSelected(true); - } - } - } - - public void setContentDescription(int i, String desc) { - mContentDescriptions.put(i, desc); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - - if (mViewPager != null) { - scrollToTab(mViewPager.getCurrentItem(), 0); - } - } - - private void scrollToTab(int tabIndex, int positionOffset) { - final int tabStripChildCount = mTabStrip.getChildCount(); - if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) { - return; - } - - View selectedChild = mTabStrip.getChildAt(tabIndex); - if (selectedChild != null) { - int targetScrollX = selectedChild.getLeft() + positionOffset; - - if (tabIndex > 0 || positionOffset > 0) { - // If we're not at the first child and are mid-scroll, make sure we obey the offset - targetScrollX -= mTitleOffset; - } - - scrollTo(targetScrollX, 0); - } - } - - private class InternalViewPagerListener implements ViewPager.OnPageChangeListener { - private int mScrollState; - - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - int tabStripChildCount = mTabStrip.getChildCount(); - if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) { - return; - } - - mTabStrip.onViewPagerPageChanged(position, positionOffset); - - View selectedTitle = mTabStrip.getChildAt(position); - int extraOffset = (selectedTitle != null) - ? (int) (positionOffset * selectedTitle.getWidth()) - : 0; - scrollToTab(position, extraOffset); - - if (mViewPagerPageChangeListener != null) { - mViewPagerPageChangeListener.onPageScrolled(position, positionOffset, - positionOffsetPixels); - } - } - - @Override - public void onPageScrollStateChanged(int state) { - mScrollState = state; - - if (mViewPagerPageChangeListener != null) { - mViewPagerPageChangeListener.onPageScrollStateChanged(state); - } - } - - @Override - public void onPageSelected(int position) { - if (mScrollState == ViewPager.SCROLL_STATE_IDLE) { - mTabStrip.onViewPagerPageChanged(position, 0f); - scrollToTab(position, 0); - } - for (int i = 0; i < mTabStrip.getChildCount(); i++) { - mTabStrip.getChildAt(i).setSelected(position == i); - } - if (mViewPagerPageChangeListener != null) { - mViewPagerPageChangeListener.onPageSelected(position); - } - } - - } - - private class TabClickListener implements View.OnClickListener { - @Override - public void onClick(View v) { - for (int i = 0; i < mTabStrip.getChildCount(); i++) { - if (v == mTabStrip.getChildAt(i)) { - mViewPager.setCurrentItem(i); - return; - } - } - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/tabs/SlidingTabStrip.java b/app/src/main/java/info/nightscout/androidaps/tabs/SlidingTabStrip.java deleted file mode 100644 index 6c8e034477..0000000000 --- a/app/src/main/java/info/nightscout/androidaps/tabs/SlidingTabStrip.java +++ /dev/null @@ -1,165 +0,0 @@ -package info.nightscout.androidaps.tabs;/* - * Copyright 2014 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.util.AttributeSet; -import android.util.TypedValue; -import android.view.View; -import android.widget.LinearLayout; - -import info.nightscout.androidaps.MainApp; -import info.nightscout.androidaps.R; - -class SlidingTabStrip extends LinearLayout { - - private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 0; - private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26; - private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 3; - - private final int mBottomBorderThickness; - private final Paint mBottomBorderPaint; - - private final int mSelectedIndicatorThickness; - private final Paint mSelectedIndicatorPaint; - - private int mSelectedPosition; - private float mSelectionOffset; - - private SlidingTabLayout.TabColorizer mCustomTabColorizer; - private final SimpleTabColorizer mDefaultTabColorizer; - - SlidingTabStrip(Context context) { - this(context, null); - } - - SlidingTabStrip(Context context, AttributeSet attrs) { - super(context, attrs); - setWillNotDraw(false); - - final float density = getResources().getDisplayMetrics().density; - - TypedValue outValue = new TypedValue(); - context.getTheme().resolveAttribute(android.R.attr.colorForeground, outValue, true); - final int themeForegroundColor = outValue.data; - - int defaultBottomBorderColor = setColorAlpha(themeForegroundColor, - DEFAULT_BOTTOM_BORDER_COLOR_ALPHA); - - mDefaultTabColorizer = new SimpleTabColorizer(); - mDefaultTabColorizer.setIndicatorColors(MainApp.gc(R.color.tabBgColorSelected)); - - mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density); - mBottomBorderPaint = new Paint(); - mBottomBorderPaint.setColor(defaultBottomBorderColor); - - mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density); - mSelectedIndicatorPaint = new Paint(); - } - - void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) { - mCustomTabColorizer = customTabColorizer; - invalidate(); - } - - void setSelectedIndicatorColors(int... colors) { - // Make sure that the custom colorizer is removed - mCustomTabColorizer = null; - mDefaultTabColorizer.setIndicatorColors(colors); - invalidate(); - } - - void onViewPagerPageChanged(int position, float positionOffset) { - mSelectedPosition = position; - mSelectionOffset = positionOffset; - invalidate(); - } - - @Override - protected void onDraw(Canvas canvas) { - final int height = getHeight(); - final int childCount = getChildCount(); - final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null - ? mCustomTabColorizer - : mDefaultTabColorizer; - - // Thick colored underline below the current selection - if (childCount > 0) { - View selectedTitle = getChildAt(mSelectedPosition); - int left = selectedTitle.getLeft(); - int right = selectedTitle.getRight(); - int color = tabColorizer.getIndicatorColor(mSelectedPosition); - - if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) { - int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1); - if (color != nextColor) { - color = blendColors(nextColor, color, mSelectionOffset); - } - - // Draw the selection partway between the tabs - View nextTitle = getChildAt(mSelectedPosition + 1); - left = (int) (mSelectionOffset * nextTitle.getLeft() + - (1.0f - mSelectionOffset) * left); - right = (int) (mSelectionOffset * nextTitle.getRight() + - (1.0f - mSelectionOffset) * right); - } - - mSelectedIndicatorPaint.setColor(color); - - canvas.drawRect(left, height - mSelectedIndicatorThickness, right, - height, mSelectedIndicatorPaint); - } - - // Thin underline along the entire bottom edge - canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint); - } - - /** - * Set the alpha value of the {@code color} to be the given {@code alpha} value. - */ - private static int setColorAlpha(int color, byte alpha) { - return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color)); - } - - /** - * Blend {@code color1} and {@code color2} using the given ratio. - * - * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend, - * 0.0 will return {@code color2}. - */ - private static int blendColors(int color1, int color2, float ratio) { - final float inverseRation = 1f - ratio; - float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation); - float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation); - float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation); - return Color.rgb((int) r, (int) g, (int) b); - } - - private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer { - private int[] mIndicatorColors; - - @Override - public final int getIndicatorColor(int position) { - return mIndicatorColors[position % mIndicatorColors.length]; - } - - void setIndicatorColors(int... colors) { - mIndicatorColors = colors; - } - } -} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/tabs/TabPageAdapter.java b/app/src/main/java/info/nightscout/androidaps/tabs/TabPageAdapter.java index 8397da97aa..c17646e901 100644 --- a/app/src/main/java/info/nightscout/androidaps/tabs/TabPageAdapter.java +++ b/app/src/main/java/info/nightscout/androidaps/tabs/TabPageAdapter.java @@ -39,6 +39,10 @@ public class TabPageAdapter extends FragmentStatePagerAdapter { return Fragment.instantiate(context, visibleFragmentList.get(position).pluginDescription.getFragmentClass()); } + public PluginBase getPluginAt(int position) { + return visibleFragmentList.get(position); + } + @Override public void finishUpdate(ViewGroup container) { try{ diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 75b54a74cb..c0f382fbb8 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,46 +1,59 @@ - + android:layout_height="match_parent" + android:clipChildren="false" + android:clipToPadding="false"> - + android:layout_height="?attr/actionBarSize" + android:background="@color/colorPrimary" + app:contentInsetEndWithActions="48dp" + app:contentInsetStartWithNavigation="48dp" + android:elevation="4dp"> - + android:background="@android:color/transparent" + app:tabIndicatorColor="#FFFFFF" + app:tabMode="scrollable" /> + + - + - + - + + - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_single_fragment.xml b/app/src/main/res/layout/activity_single_fragment.xml new file mode 100644 index 0000000000..76a157b15a --- /dev/null +++ b/app/src/main/res/layout/activity_single_fragment.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index d0fcaf9361..09bd20a631 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -1,31 +1,45 @@

+ diff --git a/app/src/main/res/menu/menu_single_fragment.xml b/app/src/main/res/menu/menu_single_fragment.xml new file mode 100644 index 0000000000..0bc5ee19b8 --- /dev/null +++ b/app/src/main/res/menu/menu_single_fragment.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml deleted file mode 100644 index 5a74f20564..0000000000 --- a/app/src/main/res/values-v21/styles.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 2807c0561c..d36a1384a0 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -33,9 +33,9 @@ #303F9F - #3F51B5 - #303F9F - #FF4081 + #212121 + #000000 + #009688 #00695c #121212 diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 47c8224673..9b772f77bd 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -2,4 +2,5 @@ 16dp 16dp + 30dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f35f648ff4..2f876f2a15 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -766,6 +766,7 @@ In xDrip+ select 640g/Eversense data source NSClient BG Basal value replaced by minimal supported value + Basal value replaced by maximum supported value BG calculation Bolus IOB calculation Basal IOB calculation @@ -1104,4 +1105,7 @@ Save options to pump On Off + Open navigation + Close navigation + Plugin preferences diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 5519bcb151..202fc7d436 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,8 +1,12 @@ - - + +