Merge branch 'dagger3' of github.com:MilosKozak/AndroidAPS into update-oref
This commit is contained in:
commit
acab0b87be
202 changed files with 5214 additions and 2582 deletions
|
@ -28,6 +28,8 @@ ext {
|
||||||
ormLiteVersion = "4.46"
|
ormLiteVersion = "4.46"
|
||||||
powermockVersion = "1.7.3"
|
powermockVersion = "1.7.3"
|
||||||
dexmakerVersion = "1.2"
|
dexmakerVersion = "1.2"
|
||||||
|
retrofit2Version = '2.8.1'
|
||||||
|
okhttp3Version="4.4.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,12 +127,6 @@ android {
|
||||||
jvmTarget = '1.8'
|
jvmTarget = '1.8'
|
||||||
}
|
}
|
||||||
lintOptions {
|
lintOptions {
|
||||||
// TODO remove once wear dependency com.google.android.gms:play-services-wearable:7.3.0
|
|
||||||
// has been upgraded (requiring significant code changes), which currently fails release
|
|
||||||
// build with a deprecation warning
|
|
||||||
// abortOnError false
|
|
||||||
// (disabled entirely to avoid reports on the error, which would still be displayed
|
|
||||||
// and it's easy to overlook that it's ignored)
|
|
||||||
checkReleaseBuilds false
|
checkReleaseBuilds false
|
||||||
disable 'MissingTranslation'
|
disable 'MissingTranslation'
|
||||||
disable 'ExtraTranslation'
|
disable 'ExtraTranslation'
|
||||||
|
@ -230,9 +226,9 @@ dependencies {
|
||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
implementation 'com.google.android.gms:play-services-wearable:17.0.0'
|
implementation 'com.google.android.gms:play-services-wearable:17.0.0'
|
||||||
implementation "com.google.android.gms:play-services-location:17.0.0"
|
implementation "com.google.android.gms:play-services-location:17.0.0"
|
||||||
implementation 'com.google.firebase:firebase-core:17.2.1'
|
implementation 'com.google.firebase:firebase-core:17.2.3'
|
||||||
implementation 'com.google.firebase:firebase-auth:19.2.0'
|
implementation 'com.google.firebase:firebase-auth:19.3.0'
|
||||||
implementation 'com.google.firebase:firebase-database:19.2.0'
|
implementation 'com.google.firebase:firebase-database:19.2.1'
|
||||||
implementation('com.crashlytics.sdk.android:crashlytics:2.10.1@aar') {
|
implementation('com.crashlytics.sdk.android:crashlytics:2.10.1@aar') {
|
||||||
transitive = true;
|
transitive = true;
|
||||||
}
|
}
|
||||||
|
@ -246,7 +242,7 @@ dependencies {
|
||||||
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
||||||
implementation 'androidx.percentlayout:percentlayout:1.0.0'
|
implementation 'androidx.percentlayout:percentlayout:1.0.0'
|
||||||
implementation "androidx.preference:preference-ktx:1.1.0"
|
implementation "androidx.preference:preference-ktx:1.1.0"
|
||||||
implementation 'com.google.android.material:material:1.0.0'
|
implementation 'com.google.android.material:material:1.1.0'
|
||||||
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
|
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
|
||||||
|
|
||||||
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
|
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
|
||||||
|
@ -257,7 +253,7 @@ dependencies {
|
||||||
exclude group: "com.google.android", module: "android"
|
exclude group: "com.google.android", module: "android"
|
||||||
}
|
}
|
||||||
implementation "org.apache.commons:commons-lang3:3.9"
|
implementation "org.apache.commons:commons-lang3:3.9"
|
||||||
implementation "org.slf4j:slf4j-api:1.7.29"
|
implementation 'org.slf4j:slf4j-api:1.7.30'
|
||||||
// Graphview cannot be upgraded
|
// Graphview cannot be upgraded
|
||||||
implementation "com.jjoe64:graphview:4.0.1"
|
implementation "com.jjoe64:graphview:4.0.1"
|
||||||
implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.2.2"
|
implementation "com.joanzapata.iconify:android-iconify-fontawesome:2.2.2"
|
||||||
|
@ -294,28 +290,23 @@ dependencies {
|
||||||
testImplementation "org.powermock:powermock-module-junit4-rule:${powermockVersion}"
|
testImplementation "org.powermock:powermock-module-junit4-rule:${powermockVersion}"
|
||||||
testImplementation "org.powermock:powermock-module-junit4:${powermockVersion}"
|
testImplementation "org.powermock:powermock-module-junit4:${powermockVersion}"
|
||||||
testImplementation "joda-time:joda-time:2.10.5"
|
testImplementation "joda-time:joda-time:2.10.5"
|
||||||
testImplementation("com.google.truth:truth:0.39") {
|
testImplementation('com.google.truth:truth:1.0.1') {
|
||||||
exclude group: "com.google.guava", module: "guava"
|
exclude group: "com.google.guava", module: "guava"
|
||||||
exclude group: "com.google.code.findbugs", module: "jsr305"
|
exclude group: "com.google.code.findbugs", module: "jsr305"
|
||||||
}
|
}
|
||||||
testImplementation "org.skyscreamer:jsonassert:1.5.0"
|
testImplementation "org.skyscreamer:jsonassert:1.5.0"
|
||||||
testImplementation "org.hamcrest:hamcrest-all:1.3"
|
testImplementation "org.hamcrest:hamcrest-all:1.3"
|
||||||
/*
|
|
||||||
testImplementation("uk.org.lidalia:slf4j-test:1.2.0") {
|
|
||||||
exclude group: "com.google.guava", module: "guava"
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||||
|
|
||||||
|
|
||||||
// new for tidepool
|
// new for tidepool
|
||||||
implementation 'com.squareup.okhttp3:okhttp:4.2.2'
|
implementation "com.squareup.okhttp3:okhttp:$okhttp3Version"
|
||||||
implementation 'com.squareup.okhttp3:logging-interceptor:4.2.2'
|
implementation "com.squareup.okhttp3:logging-interceptor:$okhttp3Version"
|
||||||
implementation "com.squareup.retrofit2:retrofit:2.6.2"
|
implementation "com.squareup.retrofit2:retrofit:$retrofit2Version"
|
||||||
implementation "com.squareup.retrofit2:adapter-rxjava2:2.6.2"
|
implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit2Version"
|
||||||
implementation "com.squareup.retrofit2:converter-gson:2.6.2"
|
implementation "com.squareup.retrofit2:converter-gson:$retrofit2Version"
|
||||||
|
|
||||||
// Phone checker
|
// Phone checker
|
||||||
implementation 'com.scottyab:rootbeer-lib:0.0.7'
|
implementation 'com.scottyab:rootbeer-lib:0.0.7'
|
||||||
|
|
|
@ -37,8 +37,6 @@ import javax.inject.Inject
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class RealPumpTest {
|
class RealPumpTest {
|
||||||
|
|
||||||
private val log = LoggerFactory.getLogger(L.CORE)
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val R_PASSWORD = 1234
|
const val R_PASSWORD = 1234
|
||||||
const val R_SERIAL = "PBB00013LR_P"
|
const val R_SERIAL = "PBB00013LR_P"
|
||||||
|
@ -120,12 +118,12 @@ class RealPumpTest {
|
||||||
preparePlugins()
|
preparePlugins()
|
||||||
|
|
||||||
while (!pump.isInitialized) {
|
while (!pump.isInitialized) {
|
||||||
log.debug("Waiting for initialization")
|
//log.debug("Waiting for initialization")
|
||||||
SystemClock.sleep(1000)
|
SystemClock.sleep(1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
log.debug("Tick")
|
//log.debug("Tick")
|
||||||
SystemClock.sleep(1000)
|
SystemClock.sleep(1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,370 +0,0 @@
|
||||||
package info.nightscout.androidaps;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.PersistableBundle;
|
|
||||||
import android.text.SpannableString;
|
|
||||||
import android.text.method.LinkMovementMethod;
|
|
||||||
import android.text.util.Linkify;
|
|
||||||
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.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import androidx.appcompat.widget.Toolbar;
|
|
||||||
import androidx.core.app.ActivityCompat;
|
|
||||||
import androidx.drawerlayout.widget.DrawerLayout;
|
|
||||||
import androidx.viewpager.widget.ViewPager;
|
|
||||||
|
|
||||||
import com.google.android.material.navigation.NavigationView;
|
|
||||||
import com.google.android.material.tabs.TabLayout;
|
|
||||||
import com.joanzapata.iconify.Iconify;
|
|
||||||
import com.joanzapata.iconify.fonts.FontAwesomeModule;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import dagger.android.AndroidInjection;
|
|
||||||
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity;
|
|
||||||
import info.nightscout.androidaps.activities.PreferencesActivity;
|
|
||||||
import info.nightscout.androidaps.activities.SingleFragmentActivity;
|
|
||||||
import info.nightscout.androidaps.activities.StatsActivity;
|
|
||||||
import info.nightscout.androidaps.events.EventAppExit;
|
|
||||||
import info.nightscout.androidaps.events.EventPreferenceChange;
|
|
||||||
import info.nightscout.androidaps.events.EventRebuildTabs;
|
|
||||||
import info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity;
|
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginType;
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
|
||||||
import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils;
|
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus;
|
|
||||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin;
|
|
||||||
import info.nightscout.androidaps.setupwizard.SetupWizardActivity;
|
|
||||||
import info.nightscout.androidaps.tabs.TabPageAdapter;
|
|
||||||
import info.nightscout.androidaps.utils.AndroidPermission;
|
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy;
|
|
||||||
import info.nightscout.androidaps.utils.LocaleHelper;
|
|
||||||
import info.nightscout.androidaps.utils.OKDialog;
|
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper;
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
|
||||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck;
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
|
||||||
|
|
||||||
import static info.nightscout.androidaps.utils.extensions.EspressoTestHelperKt.isRunningRealPumpTest;
|
|
||||||
|
|
||||||
public class MainActivity extends NoSplashAppCompatActivity {
|
|
||||||
|
|
||||||
private CompositeDisposable disposable = new CompositeDisposable();
|
|
||||||
private ActionBarDrawerToggle actionBarDrawerToggle;
|
|
||||||
private MenuItem pluginPreferencesMenuItem;
|
|
||||||
|
|
||||||
@Inject AAPSLogger aapsLogger;
|
|
||||||
@Inject RxBusWrapper rxBus;
|
|
||||||
@Inject SP sp;
|
|
||||||
@Inject ResourceHelper resourceHelper;
|
|
||||||
@Inject VersionCheckerUtils versionCheckerUtils;
|
|
||||||
@Inject SmsCommunicatorPlugin smsCommunicatorPlugin;
|
|
||||||
@Inject LoopPlugin loopPlugin;
|
|
||||||
@Inject NSSettingsStatus nsSettingsStatus;
|
|
||||||
@Inject BuildHelper buildHelper;
|
|
||||||
@Inject ActivePluginProvider activePlugin;
|
|
||||||
@Inject FabricPrivacy fabricPrivacy;
|
|
||||||
@Inject ProtectionCheck protectionCheck;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
AndroidInjection.inject(this);
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
Iconify.with(new FontAwesomeModule());
|
|
||||||
LocaleHelper.INSTANCE.update(getApplicationContext());
|
|
||||||
|
|
||||||
setContentView(R.layout.activity_main);
|
|
||||||
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();
|
|
||||||
|
|
||||||
// initialize screen wake lock
|
|
||||||
processPreferenceChange(new EventPreferenceChange(resourceHelper.gs(R.string.key_keep_screen_on)));
|
|
||||||
|
|
||||||
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) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//Check here if loop plugin is disabled. Else check via constraints
|
|
||||||
if (!loopPlugin.isEnabled(PluginType.LOOP))
|
|
||||||
versionCheckerUtils.triggerCheckVersion();
|
|
||||||
|
|
||||||
fabricPrivacy.setUserStats();
|
|
||||||
|
|
||||||
setupTabs();
|
|
||||||
setupViews();
|
|
||||||
|
|
||||||
disposable.add(rxBus
|
|
||||||
.toObservable(EventRebuildTabs.class)
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(event -> {
|
|
||||||
LocaleHelper.INSTANCE.update(getApplicationContext());
|
|
||||||
if (event.getRecreate()) {
|
|
||||||
recreate();
|
|
||||||
} else {
|
|
||||||
setupTabs();
|
|
||||||
setupViews();
|
|
||||||
}
|
|
||||||
setWakeLock();
|
|
||||||
}, exception -> fabricPrivacy.logException(exception))
|
|
||||||
);
|
|
||||||
disposable.add(rxBus
|
|
||||||
.toObservable(EventPreferenceChange.class)
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(this::processPreferenceChange, exception -> fabricPrivacy.logException(exception))
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!sp.getBoolean(R.string.key_setupwizard_processed, false) && !isRunningRealPumpTest()) {
|
|
||||||
Intent intent = new Intent(this, SetupWizardActivity.class);
|
|
||||||
startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
AndroidPermission.notifyForStoragePermission(this);
|
|
||||||
AndroidPermission.notifyForBatteryOptimizationPermission(this);
|
|
||||||
if (Config.PUMPDRIVERS) {
|
|
||||||
AndroidPermission.notifyForLocationPermissions(this);
|
|
||||||
AndroidPermission.notifyForSMSPermissions(this, smsCommunicatorPlugin);
|
|
||||||
AndroidPermission.notifyForSystemWindowPermissions(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
public void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
disposable.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
protectionCheck.queryProtection(this, ProtectionCheck.Protection.APPLICATION, null, this::finish, this::finish);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setWakeLock() {
|
|
||||||
boolean keepScreenOn = sp.getBoolean(R.string.key_keep_screen_on, false);
|
|
||||||
if (keepScreenOn)
|
|
||||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
||||||
else
|
|
||||||
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void processPreferenceChange(final EventPreferenceChange ev) {
|
|
||||||
if (ev.isChanged(resourceHelper, R.string.key_keep_screen_on))
|
|
||||||
setWakeLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupViews() {
|
|
||||||
TabPageAdapter pageAdapter = new TabPageAdapter(getSupportFragmentManager(), this);
|
|
||||||
NavigationView navigationView = findViewById(R.id.navigation_view);
|
|
||||||
navigationView.setNavigationItemSelectedListener(menuItem -> true);
|
|
||||||
Menu menu = navigationView.getMenu();
|
|
||||||
menu.clear();
|
|
||||||
for (PluginBase p : activePlugin.getPluginsList()) {
|
|
||||||
pageAdapter.registerNewFragment(p);
|
|
||||||
if (p.hasFragment() && !p.isFragmentVisible() && p.isEnabled(p.getPluginDescription().getType()) && !p.getPluginDescription().neverVisible) {
|
|
||||||
MenuItem menuItem = menu.add(p.getName());
|
|
||||||
menuItem.setCheckable(true);
|
|
||||||
menuItem.setOnMenuItemClickListener(item -> {
|
|
||||||
Intent intent = new Intent(this, SingleFragmentActivity.class);
|
|
||||||
intent.putExtra("plugin", activePlugin.getPluginsList().indexOf(p));
|
|
||||||
startActivity(intent);
|
|
||||||
((DrawerLayout) findViewById(R.id.drawer_layout)).closeDrawers();
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ViewPager mPager = findViewById(R.id.pager);
|
|
||||||
mPager.setAdapter(pageAdapter);
|
|
||||||
//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())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
||||||
if (permissions.length != 0) {
|
|
||||||
if (ActivityCompat.checkSelfPermission(this, permissions[0]) == PackageManager.PERMISSION_GRANTED) {
|
|
||||||
switch (requestCode) {
|
|
||||||
case AndroidPermission.CASE_STORAGE:
|
|
||||||
//show dialog after permission is granted
|
|
||||||
OKDialog.show(this, "", resourceHelper.gs(R.string.alert_dialog_storage_permission_text));
|
|
||||||
break;
|
|
||||||
case AndroidPermission.CASE_LOCATION:
|
|
||||||
case AndroidPermission.CASE_SMS:
|
|
||||||
case AndroidPermission.CASE_BATTERY:
|
|
||||||
case AndroidPermission.CASE_PHONE_STATE:
|
|
||||||
case AndroidPermission.CASE_SYSTEM_WINDOW:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean dispatchTouchEvent(MotionEvent event) {
|
|
||||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
|
||||||
View v = getCurrentFocus();
|
|
||||||
if (v instanceof EditText) {
|
|
||||||
Rect outRect = new Rect();
|
|
||||||
v.getGlobalVisibleRect(outRect);
|
|
||||||
if (!outRect.contains((int) event.getRawX(), (int) event.getRawY())) {
|
|
||||||
v.clearFocus();
|
|
||||||
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
||||||
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.dispatchTouchEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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:
|
|
||||||
protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, () -> {
|
|
||||||
Intent i = new Intent(this, PreferencesActivity.class);
|
|
||||||
i.putExtra("id", -1);
|
|
||||||
startActivity(i);
|
|
||||||
});
|
|
||||||
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_about:
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
||||||
builder.setTitle(resourceHelper.gs(R.string.app_name) + " " + BuildConfig.VERSION);
|
|
||||||
builder.setIcon(resourceHelper.getIcon());
|
|
||||||
String message = "Build: " + BuildConfig.BUILDVERSION + "\n";
|
|
||||||
message += "Flavor: " + BuildConfig.FLAVOR + BuildConfig.BUILD_TYPE + "\n";
|
|
||||||
message += resourceHelper.gs(R.string.configbuilder_nightscoutversion_label) + " " + nsSettingsStatus.getNightscoutVersionName();
|
|
||||||
if (buildHelper.isEngineeringMode())
|
|
||||||
message += "\n" + resourceHelper.gs(R.string.engineering_mode_enabled);
|
|
||||||
message += resourceHelper.gs(R.string.about_link_urls);
|
|
||||||
final SpannableString messageSpanned = new SpannableString(message);
|
|
||||||
Linkify.addLinks(messageSpanned, Linkify.WEB_URLS);
|
|
||||||
builder.setMessage(messageSpanned);
|
|
||||||
builder.setPositiveButton(resourceHelper.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:
|
|
||||||
aapsLogger.debug(LTag.CORE, "Exiting");
|
|
||||||
rxBus.send(new EventAppExit());
|
|
||||||
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());
|
|
||||||
protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, () -> {
|
|
||||||
Intent i = new Intent(this, PreferencesActivity.class);
|
|
||||||
i.putExtra("id", plugin.getPreferencesId());
|
|
||||||
startActivity(i);
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
/*
|
|
||||||
case R.id.nav_survey:
|
|
||||||
startActivity(new Intent(this, SurveyActivity.class));
|
|
||||||
return true;
|
|
||||||
*/
|
|
||||||
case R.id.nav_stats:
|
|
||||||
startActivity(new Intent(this, StatsActivity.class));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return actionBarDrawerToggle.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
333
app/src/main/java/info/nightscout/androidaps/MainActivity.kt
Normal file
333
app/src/main/java/info/nightscout/androidaps/MainActivity.kt
Normal file
|
@ -0,0 +1,333 @@
|
||||||
|
package info.nightscout.androidaps
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.PersistableBundle
|
||||||
|
import android.text.SpannableString
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
|
import android.text.util.Linkify
|
||||||
|
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.LinearLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.app.ActionBarDrawerToggle
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
|
import androidx.viewpager.widget.ViewPager
|
||||||
|
import com.google.android.material.navigation.NavigationView
|
||||||
|
import com.google.android.material.tabs.TabLayout
|
||||||
|
import com.joanzapata.iconify.Iconify
|
||||||
|
import com.joanzapata.iconify.fonts.FontAwesomeModule
|
||||||
|
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
|
||||||
|
import info.nightscout.androidaps.activities.PreferencesActivity
|
||||||
|
import info.nightscout.androidaps.activities.SingleFragmentActivity
|
||||||
|
import info.nightscout.androidaps.activities.StatsActivity
|
||||||
|
import info.nightscout.androidaps.events.EventAppExit
|
||||||
|
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||||
|
import info.nightscout.androidaps.events.EventRebuildTabs
|
||||||
|
import info.nightscout.androidaps.historyBrowser.HistoryBrowseActivity
|
||||||
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||||
|
import info.nightscout.androidaps.interfaces.PluginType
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils
|
||||||
|
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
|
||||||
|
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
|
||||||
|
import info.nightscout.androidaps.setupwizard.SetupWizardActivity
|
||||||
|
import info.nightscout.androidaps.tabs.TabPageAdapter
|
||||||
|
import info.nightscout.androidaps.utils.AndroidPermission
|
||||||
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
|
import info.nightscout.androidaps.utils.LocaleHelper.update
|
||||||
|
import info.nightscout.androidaps.utils.OKDialog.show
|
||||||
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
|
import info.nightscout.androidaps.utils.extensions.isRunningRealPumpTest
|
||||||
|
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
class MainActivity : NoSplashAppCompatActivity() {
|
||||||
|
private val disposable = CompositeDisposable()
|
||||||
|
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
|
@Inject lateinit var androidPermission: AndroidPermission
|
||||||
|
@Inject lateinit var sp: SP
|
||||||
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
|
@Inject lateinit var versionCheckerUtils: VersionCheckerUtils
|
||||||
|
@Inject lateinit var smsCommunicatorPlugin: SmsCommunicatorPlugin
|
||||||
|
@Inject lateinit var loopPlugin: LoopPlugin
|
||||||
|
@Inject lateinit var nsSettingsStatus: NSSettingsStatus
|
||||||
|
@Inject lateinit var buildHelper: BuildHelper
|
||||||
|
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||||
|
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||||
|
@Inject lateinit var protectionCheck: ProtectionCheck
|
||||||
|
|
||||||
|
private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle
|
||||||
|
private var pluginPreferencesMenuItem: MenuItem? = null
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
Iconify.with(FontAwesomeModule())
|
||||||
|
update(applicationContext)
|
||||||
|
setContentView(R.layout.activity_main)
|
||||||
|
setSupportActionBar(toolbar)
|
||||||
|
supportActionBar?.setDisplayShowTitleEnabled(false)
|
||||||
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
supportActionBar?.setHomeButtonEnabled(true)
|
||||||
|
actionBarDrawerToggle = ActionBarDrawerToggle(this, drawer_layout, R.string.open_navigation, R.string.close_navigation).also {
|
||||||
|
drawer_layout.addDrawerListener(it)
|
||||||
|
it.syncState()
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize screen wake lock
|
||||||
|
processPreferenceChange(EventPreferenceChange(resourceHelper.gs(R.string.key_keep_screen_on)))
|
||||||
|
pager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
|
||||||
|
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
|
||||||
|
override fun onPageSelected(position: Int) {
|
||||||
|
checkPluginPreferences(pager)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPageScrollStateChanged(state: Int) {}
|
||||||
|
})
|
||||||
|
|
||||||
|
//Check here if loop plugin is disabled. Else check via constraints
|
||||||
|
if (!loopPlugin.isEnabled(PluginType.LOOP)) versionCheckerUtils.triggerCheckVersion()
|
||||||
|
fabricPrivacy.setUserStats()
|
||||||
|
setupTabs()
|
||||||
|
setupViews()
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventRebuildTabs::class.java)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe({
|
||||||
|
update(applicationContext)
|
||||||
|
if (it.recreate) recreate()
|
||||||
|
else {
|
||||||
|
setupTabs()
|
||||||
|
setupViews()
|
||||||
|
}
|
||||||
|
setWakeLock()
|
||||||
|
}) { fabricPrivacy.logException(it) }
|
||||||
|
)
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventPreferenceChange::class.java)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe({ processPreferenceChange(it) }) { fabricPrivacy.logException(it) }
|
||||||
|
)
|
||||||
|
if (!sp.getBoolean(R.string.key_setupwizard_processed, false) && !isRunningRealPumpTest()) {
|
||||||
|
val intent = Intent(this, SetupWizardActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
androidPermission.notifyForStoragePermission(this)
|
||||||
|
androidPermission.notifyForBatteryOptimizationPermission(this)
|
||||||
|
if (Config.PUMPDRIVERS) {
|
||||||
|
androidPermission.notifyForLocationPermissions(this)
|
||||||
|
androidPermission.notifyForSMSPermissions(this, smsCommunicatorPlugin)
|
||||||
|
androidPermission.notifyForSystemWindowPermissions(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkPluginPreferences(viewPager: ViewPager) {
|
||||||
|
pluginPreferencesMenuItem?.isEnabled = (viewPager.adapter as TabPageAdapter).getPluginAt(viewPager.currentItem).preferencesId != -1
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPostCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
|
||||||
|
super.onPostCreate(savedInstanceState, persistentState)
|
||||||
|
actionBarDrawerToggle.syncState()
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
disposable.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
protectionCheck.queryProtection(this, ProtectionCheck.Protection.APPLICATION, null, Runnable { finish() }, Runnable { finish() })
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setWakeLock() {
|
||||||
|
val keepScreenOn = sp.getBoolean(R.string.key_keep_screen_on, false)
|
||||||
|
if (keepScreenOn) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) else window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun processPreferenceChange(ev: EventPreferenceChange) {
|
||||||
|
if (ev.isChanged(resourceHelper, R.string.key_keep_screen_on)) setWakeLock()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupViews() {
|
||||||
|
val pageAdapter = TabPageAdapter(supportFragmentManager, this)
|
||||||
|
val navigationView = findViewById<NavigationView>(R.id.navigation_view)
|
||||||
|
navigationView.setNavigationItemSelectedListener { true }
|
||||||
|
val menu = navigationView.menu.also { it.clear() }
|
||||||
|
for (p in activePlugin.pluginsList) {
|
||||||
|
pageAdapter.registerNewFragment(p)
|
||||||
|
if (p.hasFragment() && !p.isFragmentVisible() && p.isEnabled(p.pluginDescription.type) && !p.pluginDescription.neverVisible) {
|
||||||
|
val menuItem = menu.add(p.name)
|
||||||
|
menuItem.isCheckable = true
|
||||||
|
menuItem.setOnMenuItemClickListener {
|
||||||
|
val intent = Intent(this, SingleFragmentActivity::class.java)
|
||||||
|
intent.putExtra("plugin", activePlugin.pluginsList.indexOf(p))
|
||||||
|
startActivity(intent)
|
||||||
|
(findViewById<View>(R.id.drawer_layout) as DrawerLayout).closeDrawers()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val mPager = findViewById<ViewPager>(R.id.pager)
|
||||||
|
mPager.adapter = pageAdapter
|
||||||
|
//if (switchToLast)
|
||||||
|
// mPager.setCurrentItem(pageAdapter.getCount() - 1, false);
|
||||||
|
checkPluginPreferences(mPager)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupTabs() {
|
||||||
|
val viewPager = findViewById<ViewPager>(R.id.pager)
|
||||||
|
val normalTabs = findViewById<TabLayout>(R.id.tabs_normal)
|
||||||
|
normalTabs.setupWithViewPager(viewPager, true)
|
||||||
|
val compactTabs = findViewById<TabLayout>(R.id.tabs_compact)
|
||||||
|
compactTabs.setupWithViewPager(viewPager, true)
|
||||||
|
val toolbar = findViewById<Toolbar>(R.id.toolbar)
|
||||||
|
if (sp.getBoolean(R.string.key_short_tabtitles, false)) {
|
||||||
|
normalTabs.visibility = View.GONE
|
||||||
|
compactTabs.visibility = View.VISIBLE
|
||||||
|
toolbar.layoutParams = LinearLayout.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT, resources.getDimension(R.dimen.compact_height).toInt())
|
||||||
|
} else {
|
||||||
|
normalTabs.visibility = View.VISIBLE
|
||||||
|
compactTabs.visibility = View.GONE
|
||||||
|
val typedValue = TypedValue()
|
||||||
|
if (theme.resolveAttribute(R.attr.actionBarSize, typedValue, true)) {
|
||||||
|
toolbar.layoutParams = LinearLayout.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT,
|
||||||
|
TypedValue.complexToDimensionPixelSize(typedValue.data, resources.displayMetrics))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||||
|
if (permissions.isNotEmpty()) {
|
||||||
|
if (ActivityCompat.checkSelfPermission(this, permissions[0]) == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
when (requestCode) {
|
||||||
|
AndroidPermission.CASE_STORAGE -> //show dialog after permission is granted
|
||||||
|
show(this, "", resourceHelper.gs(R.string.alert_dialog_storage_permission_text))
|
||||||
|
|
||||||
|
AndroidPermission.CASE_LOCATION, AndroidPermission.CASE_SMS, AndroidPermission.CASE_BATTERY, AndroidPermission.CASE_PHONE_STATE, AndroidPermission.CASE_SYSTEM_WINDOW -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
||||||
|
if (event.action == MotionEvent.ACTION_DOWN) {
|
||||||
|
val v = currentFocus
|
||||||
|
if (v is EditText) {
|
||||||
|
val outRect = Rect()
|
||||||
|
v.getGlobalVisibleRect(outRect)
|
||||||
|
if (!outRect.contains(event.rawX.toInt(), event.rawY.toInt())) {
|
||||||
|
v.clearFocus()
|
||||||
|
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
|
imm.hideSoftInputFromWindow(v.getWindowToken(), 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.dispatchTouchEvent(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
|
menuInflater.inflate(R.menu.menu_main, menu)
|
||||||
|
pluginPreferencesMenuItem = menu.findItem(R.id.nav_plugin_preferences)
|
||||||
|
checkPluginPreferences(findViewById(R.id.pager))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.nav_preferences -> {
|
||||||
|
protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, Runnable {
|
||||||
|
val i = Intent(this, PreferencesActivity::class.java)
|
||||||
|
i.putExtra("id", -1)
|
||||||
|
startActivity(i)
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.nav_historybrowser -> {
|
||||||
|
startActivity(Intent(this, HistoryBrowseActivity::class.java))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.nav_setupwizard -> {
|
||||||
|
startActivity(Intent(this, SetupWizardActivity::class.java))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.nav_about -> {
|
||||||
|
var message = "Build: ${BuildConfig.BUILDVERSION}\n"
|
||||||
|
message += "Flavor: ${BuildConfig.FLAVOR}${BuildConfig.BUILD_TYPE}\n"
|
||||||
|
message += "${resourceHelper.gs(R.string.configbuilder_nightscoutversion_label)} ${nsSettingsStatus.nightscoutVersionName}"
|
||||||
|
if (buildHelper.isEngineeringMode()) message += "\n${resourceHelper.gs(R.string.engineering_mode_enabled)}"
|
||||||
|
message += resourceHelper.gs(R.string.about_link_urls)
|
||||||
|
val messageSpanned = SpannableString(message)
|
||||||
|
Linkify.addLinks(messageSpanned, Linkify.WEB_URLS)
|
||||||
|
AlertDialog.Builder(this)
|
||||||
|
.setTitle(resourceHelper.gs(R.string.app_name) + " " + BuildConfig.VERSION)
|
||||||
|
.setIcon(resourceHelper.getIcon())
|
||||||
|
.setMessage(messageSpanned)
|
||||||
|
.setPositiveButton(resourceHelper.gs(R.string.ok), null)
|
||||||
|
.create().also {
|
||||||
|
it.show()
|
||||||
|
(it.findViewById<View>(android.R.id.message) as TextView).movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.nav_exit -> {
|
||||||
|
aapsLogger.debug(LTag.CORE, "Exiting")
|
||||||
|
rxBus.send(EventAppExit())
|
||||||
|
finish()
|
||||||
|
System.runFinalization()
|
||||||
|
exitProcess(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.nav_plugin_preferences -> {
|
||||||
|
val viewPager = findViewById<ViewPager>(R.id.pager)
|
||||||
|
val plugin = (viewPager.adapter as TabPageAdapter).getPluginAt(viewPager.currentItem)
|
||||||
|
protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, Runnable {
|
||||||
|
val i = Intent(this, PreferencesActivity::class.java)
|
||||||
|
i.putExtra("id", plugin.preferencesId)
|
||||||
|
startActivity(i)
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
R.id.nav_survey -> {
|
||||||
|
startActivity(Intent(this, SurveyActivity::class.java))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
R.id.nav_stats -> {
|
||||||
|
startActivity(Intent(this, StatsActivity::class.java))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return actionBarDrawerToggle.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package info.nightscout.androidaps;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
@ -25,6 +26,8 @@ import net.danlew.android.joda.JodaTimeAndroid;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import dagger.android.AndroidInjector;
|
import dagger.android.AndroidInjector;
|
||||||
|
@ -33,69 +36,20 @@ import dagger.android.HasAndroidInjector;
|
||||||
import info.nightscout.androidaps.data.Profile;
|
import info.nightscout.androidaps.data.Profile;
|
||||||
import info.nightscout.androidaps.db.DatabaseHelper;
|
import info.nightscout.androidaps.db.DatabaseHelper;
|
||||||
import info.nightscout.androidaps.dependencyInjection.DaggerAppComponent;
|
import info.nightscout.androidaps.dependencyInjection.DaggerAppComponent;
|
||||||
|
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
import info.nightscout.androidaps.logging.LTag;
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
|
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.PluginStore;
|
import info.nightscout.androidaps.plugins.configBuilder.PluginStore;
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;
|
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;
|
||||||
import info.nightscout.androidaps.plugins.constraints.dstHelper.DstHelperPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.constraints.signatureVerifier.SignatureVerifierPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.constraints.storage.StorageConstraintPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils;
|
import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils;
|
||||||
import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.general.careportal.CareportalPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.general.dataBroadcaster.DataBroadcastPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.general.food.FoodPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
|
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
|
||||||
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin;
|
import info.nightscout.androidaps.receivers.BTReceiver;
|
||||||
import info.nightscout.androidaps.plugins.general.persistentNotification.PersistentNotificationPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.general.tidepool.TidepoolPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.general.xdripStatusline.StatusLinePlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.insulin.InsulinOrefFreePeakPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.insulin.InsulinOrefRapidActingPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.insulin.InsulinOrefUltraRapidActingPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.danaR.DanaRPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.danaRS.DanaRSPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.danaRv2.DanaRv2Plugin;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.mdi.MDIPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin;
|
|
||||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
|
|
||||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.source.DexcomPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.source.EversensePlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.source.GlimpPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.source.MM640gPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.source.NSClientSourcePlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.source.PoctechPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.source.RandomBgPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.source.TomatoPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.source.XdripPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
|
||||||
import info.nightscout.androidaps.receivers.ChargingStateReceiver;
|
import info.nightscout.androidaps.receivers.ChargingStateReceiver;
|
||||||
import info.nightscout.androidaps.receivers.DataReceiver;
|
import info.nightscout.androidaps.receivers.DataReceiver;
|
||||||
import info.nightscout.androidaps.receivers.KeepAliveReceiver;
|
import info.nightscout.androidaps.receivers.KeepAliveReceiver;
|
||||||
import info.nightscout.androidaps.receivers.NetworkChangeReceiver;
|
import info.nightscout.androidaps.receivers.NetworkChangeReceiver;
|
||||||
|
import info.nightscout.androidaps.receivers.ReceiverStatusStore;
|
||||||
import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver;
|
import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver;
|
||||||
import info.nightscout.androidaps.services.Intents;
|
import info.nightscout.androidaps.services.Intents;
|
||||||
import info.nightscout.androidaps.utils.ActivityMonitor;
|
import info.nightscout.androidaps.utils.ActivityMonitor;
|
||||||
|
@ -114,9 +68,6 @@ public class MainApp extends DaggerApplication {
|
||||||
|
|
||||||
static DatabaseHelper sDatabaseHelper = null;
|
static DatabaseHelper sDatabaseHelper = null;
|
||||||
|
|
||||||
DataReceiver dataReceiver = new DataReceiver();
|
|
||||||
TimeDateOrTZChangeReceiver timeDateOrTZChangeReceiver;
|
|
||||||
|
|
||||||
private String CHANNEL_ID = "AndroidAPS-Ongoing"; // TODO: move to OngoingNotificationProvider (and dagger)
|
private String CHANNEL_ID = "AndroidAPS-Ongoing"; // TODO: move to OngoingNotificationProvider (and dagger)
|
||||||
private int ONGOING_NOTIFICATION_ID = 4711; // TODO: move to OngoingNotificationProvider (and dagger)
|
private int ONGOING_NOTIFICATION_ID = 4711; // TODO: move to OngoingNotificationProvider (and dagger)
|
||||||
private Notification notification; // TODO: move to OngoingNotificationProvider (and dagger)
|
private Notification notification; // TODO: move to OngoingNotificationProvider (and dagger)
|
||||||
|
@ -124,6 +75,7 @@ public class MainApp extends DaggerApplication {
|
||||||
@Inject PluginStore pluginStore;
|
@Inject PluginStore pluginStore;
|
||||||
@Inject public HasAndroidInjector injector;
|
@Inject public HasAndroidInjector injector;
|
||||||
@Inject AAPSLogger aapsLogger;
|
@Inject AAPSLogger aapsLogger;
|
||||||
|
@Inject ReceiverStatusStore receiverStatusStore;
|
||||||
@Inject ActivityMonitor activityMonitor;
|
@Inject ActivityMonitor activityMonitor;
|
||||||
@Inject FabricPrivacy fabricPrivacy;
|
@Inject FabricPrivacy fabricPrivacy;
|
||||||
@Inject ResourceHelper resourceHelper;
|
@Inject ResourceHelper resourceHelper;
|
||||||
|
@ -131,60 +83,9 @@ public class MainApp extends DaggerApplication {
|
||||||
@Inject SP sp;
|
@Inject SP sp;
|
||||||
@Inject ProfileFunction profileFunction;
|
@Inject ProfileFunction profileFunction;
|
||||||
|
|
||||||
@Inject ActionsPlugin actionsPlugin;
|
|
||||||
@Inject AutomationPlugin automationPlugin;
|
|
||||||
@Inject ComboPlugin comboPlugin;
|
|
||||||
@Inject CareportalPlugin careportalPlugin;
|
|
||||||
@Inject ConfigBuilderPlugin configBuilderPlugin;
|
@Inject ConfigBuilderPlugin configBuilderPlugin;
|
||||||
@Inject DanaRPlugin danaRPlugin;
|
|
||||||
@Inject DanaRSPlugin danaRSPlugin;
|
|
||||||
@Inject DanaRv2Plugin danaRv2Plugin;
|
|
||||||
@Inject DanaRKoreanPlugin danaRKoreanPlugin;
|
|
||||||
@Inject DataBroadcastPlugin dataBroadcastPlugin;
|
|
||||||
@Inject DstHelperPlugin dstHelperPlugin;
|
|
||||||
@Inject FoodPlugin foodPlugin;
|
|
||||||
@Inject InsulinOrefFreePeakPlugin insulinOrefFreePeakPlugin;
|
|
||||||
@Inject InsulinOrefRapidActingPlugin insulinOrefRapidActingPlugin;
|
|
||||||
@Inject InsulinOrefUltraRapidActingPlugin insulinOrefUltraRapidActingPlugin;
|
|
||||||
@Inject IobCobCalculatorPlugin iobCobCalculatorPlugin;
|
|
||||||
@Inject LocalInsightPlugin localInsightPlugin;
|
|
||||||
@Inject LocalProfilePlugin localProfilePlugin;
|
|
||||||
@Inject LoopPlugin loopPlugin;
|
|
||||||
@Inject MedtronicPumpPlugin medtronicPumpPlugin;
|
|
||||||
@Inject MDIPlugin mdiPlugin;
|
|
||||||
@Inject NSProfilePlugin nsProfilePlugin;
|
|
||||||
@Inject ObjectivesPlugin objectivesPlugin;
|
|
||||||
@Inject SafetyPlugin safetyPlugin;
|
|
||||||
@Inject SmsCommunicatorPlugin smsCommunicatorPlugin;
|
|
||||||
@Inject OpenAPSMAPlugin openAPSMAPlugin;
|
|
||||||
@Inject OpenAPSAMAPlugin openAPSAMAPlugin;
|
|
||||||
@Inject OpenAPSSMBPlugin openAPSSMBPlugin;
|
|
||||||
@Inject OverviewPlugin overviewPlugin;
|
|
||||||
@Inject PersistentNotificationPlugin persistentNotificationPlugin;
|
|
||||||
@Inject RandomBgPlugin randomBgPlugin;
|
|
||||||
@Inject SensitivityOref1Plugin sensitivityOref1Plugin;
|
|
||||||
@Inject SensitivityAAPSPlugin sensitivityAAPSPlugin;
|
|
||||||
@Inject SensitivityOref0Plugin sensitivityOref0Plugin;
|
|
||||||
@Inject SensitivityWeightedAveragePlugin sensitivityWeightedAveragePlugin;
|
|
||||||
@Inject SignatureVerifierPlugin signatureVerifierPlugin;
|
|
||||||
@Inject StorageConstraintPlugin storageConstraintPlugin;
|
|
||||||
@Inject DexcomPlugin dexcomPlugin;
|
|
||||||
@Inject EversensePlugin eversensePlugin;
|
|
||||||
@Inject GlimpPlugin glimpPlugin;
|
|
||||||
@Inject MaintenancePlugin maintenancePlugin;
|
|
||||||
@Inject MM640gPlugin mM640GPlugin;
|
|
||||||
@Inject NSClientPlugin nsClientPlugin;
|
|
||||||
@Inject NSClientSourcePlugin nSClientSourcePlugin;
|
|
||||||
@Inject PoctechPlugin poctechPlugin;
|
|
||||||
@Inject TomatoPlugin tomatoPlugin;
|
|
||||||
@Inject XdripPlugin xdripPlugin;
|
|
||||||
@Inject StatusLinePlugin statusLinePlugin;
|
|
||||||
@Inject TidepoolPlugin tidepoolPlugin;
|
|
||||||
@Inject TreatmentsPlugin treatmentsPlugin;
|
|
||||||
@Inject VirtualPumpPlugin virtualPumpPlugin;
|
|
||||||
@Inject VersionCheckerPlugin versionCheckerPlugin;
|
|
||||||
@Inject WearPlugin wearPlugin;
|
|
||||||
@Inject KeepAliveReceiver.KeepAliveManager keepAliveManager;
|
@Inject KeepAliveReceiver.KeepAliveManager keepAliveManager;
|
||||||
|
@Inject List<PluginBase> plugins;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
|
@ -197,15 +98,13 @@ public class MainApp extends DaggerApplication {
|
||||||
generateEmptyNotification();
|
generateEmptyNotification();
|
||||||
sDatabaseHelper = OpenHelperManager.getHelper(sInstance, DatabaseHelper.class);
|
sDatabaseHelper = OpenHelperManager.getHelper(sInstance, DatabaseHelper.class);
|
||||||
|
|
||||||
/* TODO: put back
|
|
||||||
Thread.setDefaultUncaughtExceptionHandler((thread, ex) -> {
|
Thread.setDefaultUncaughtExceptionHandler((thread, ex) -> {
|
||||||
if (ex instanceof InternalError) {
|
if (ex instanceof InternalError) {
|
||||||
// usually the app trying to spawn a thread while being killed
|
// usually the app trying to spawn a thread while being killed
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.error("Uncaught exception crashing app", ex);
|
aapsLogger.error("Uncaught exception crashing app", ex);
|
||||||
});
|
});
|
||||||
*/
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (fabricPrivacy.fabricEnabled()) {
|
if (fabricPrivacy.fabricEnabled()) {
|
||||||
|
@ -232,62 +131,7 @@ public class MainApp extends DaggerApplication {
|
||||||
versionCheckersUtils.triggerCheckVersion();
|
versionCheckersUtils.triggerCheckVersion();
|
||||||
|
|
||||||
// Register all tabs in app here
|
// Register all tabs in app here
|
||||||
pluginStore.add(overviewPlugin);
|
pluginStore.setPlugins(plugins);
|
||||||
pluginStore.add(iobCobCalculatorPlugin);
|
|
||||||
if (!Config.NSCLIENT) pluginStore.add(actionsPlugin);
|
|
||||||
pluginStore.add(insulinOrefRapidActingPlugin);
|
|
||||||
pluginStore.add(insulinOrefUltraRapidActingPlugin);
|
|
||||||
pluginStore.add(insulinOrefFreePeakPlugin);
|
|
||||||
pluginStore.add(sensitivityOref0Plugin);
|
|
||||||
pluginStore.add(sensitivityAAPSPlugin);
|
|
||||||
pluginStore.add(sensitivityWeightedAveragePlugin);
|
|
||||||
pluginStore.add(sensitivityOref1Plugin);
|
|
||||||
if (Config.PUMPDRIVERS) pluginStore.add(danaRPlugin);
|
|
||||||
if (Config.PUMPDRIVERS) pluginStore.add(danaRKoreanPlugin);
|
|
||||||
if (Config.PUMPDRIVERS) pluginStore.add(danaRv2Plugin);
|
|
||||||
if (Config.PUMPDRIVERS) pluginStore.add(danaRSPlugin);
|
|
||||||
if (Config.PUMPDRIVERS) pluginStore.add(localInsightPlugin);
|
|
||||||
if (Config.PUMPDRIVERS) pluginStore.add(comboPlugin);
|
|
||||||
if (Config.PUMPDRIVERS) pluginStore.add(medtronicPumpPlugin);
|
|
||||||
if (!Config.NSCLIENT) pluginStore.add(mdiPlugin);
|
|
||||||
if (!Config.NSCLIENT) pluginStore.add(virtualPumpPlugin);
|
|
||||||
if (Config.NSCLIENT) pluginStore.add(careportalPlugin);
|
|
||||||
if (Config.APS) pluginStore.add(loopPlugin);
|
|
||||||
if (Config.APS) pluginStore.add(openAPSMAPlugin);
|
|
||||||
if (Config.APS) pluginStore.add(openAPSAMAPlugin);
|
|
||||||
if (Config.APS) pluginStore.add(openAPSSMBPlugin);
|
|
||||||
pluginStore.add(nsProfilePlugin);
|
|
||||||
if (!Config.NSCLIENT) pluginStore.add(localProfilePlugin);
|
|
||||||
pluginStore.add(treatmentsPlugin);
|
|
||||||
if (!Config.NSCLIENT) pluginStore.add(safetyPlugin);
|
|
||||||
if (!Config.NSCLIENT) pluginStore.add(versionCheckerPlugin);
|
|
||||||
if (Config.APS) pluginStore.add(storageConstraintPlugin);
|
|
||||||
if (Config.APS) pluginStore.add(signatureVerifierPlugin);
|
|
||||||
if (Config.APS) pluginStore.add(objectivesPlugin);
|
|
||||||
pluginStore.add(xdripPlugin);
|
|
||||||
pluginStore.add(nSClientSourcePlugin);
|
|
||||||
pluginStore.add(mM640GPlugin);
|
|
||||||
pluginStore.add(glimpPlugin);
|
|
||||||
pluginStore.add(dexcomPlugin);
|
|
||||||
pluginStore.add(poctechPlugin);
|
|
||||||
pluginStore.add(tomatoPlugin);
|
|
||||||
pluginStore.add(eversensePlugin);
|
|
||||||
pluginStore.add(randomBgPlugin);
|
|
||||||
if (!Config.NSCLIENT) pluginStore.add(smsCommunicatorPlugin);
|
|
||||||
pluginStore.add(foodPlugin);
|
|
||||||
|
|
||||||
pluginStore.add(wearPlugin);
|
|
||||||
pluginStore.add(statusLinePlugin);
|
|
||||||
pluginStore.add(persistentNotificationPlugin);
|
|
||||||
pluginStore.add(nsClientPlugin);
|
|
||||||
// if (engineeringMode) pluginsList.add(tidepoolPlugin);
|
|
||||||
pluginStore.add(maintenancePlugin);
|
|
||||||
pluginStore.add(automationPlugin);
|
|
||||||
pluginStore.add(dstHelperPlugin);
|
|
||||||
pluginStore.add(dataBroadcastPlugin);
|
|
||||||
|
|
||||||
pluginStore.add(configBuilderPlugin);
|
|
||||||
|
|
||||||
configBuilderPlugin.initialize();
|
configBuilderPlugin.initialize();
|
||||||
|
|
||||||
NSUpload.uploadAppStart();
|
NSUpload.uploadAppStart();
|
||||||
|
@ -330,24 +174,38 @@ public class MainApp extends DaggerApplication {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerLocalBroadcastReceiver() {
|
private void registerLocalBroadcastReceiver() {
|
||||||
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
|
IntentFilter filter = new IntentFilter();
|
||||||
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_NEW_TREATMENT));
|
filter.addAction(Intents.ACTION_NEW_TREATMENT);
|
||||||
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_CHANGED_TREATMENT));
|
filter.addAction(Intents.ACTION_CHANGED_TREATMENT);
|
||||||
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_REMOVED_TREATMENT));
|
filter.addAction(Intents.ACTION_REMOVED_TREATMENT);
|
||||||
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_NEW_SGV));
|
filter.addAction(Intents.ACTION_NEW_SGV);
|
||||||
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_NEW_PROFILE));
|
filter.addAction(Intents.ACTION_NEW_PROFILE);
|
||||||
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_NEW_MBG));
|
filter.addAction(Intents.ACTION_NEW_MBG);
|
||||||
lbm.registerReceiver(dataReceiver, new IntentFilter(Intents.ACTION_NEW_CAL));
|
filter.addAction(Intents.ACTION_NEW_CAL);
|
||||||
|
LocalBroadcastManager.getInstance(this).registerReceiver(new DataReceiver(), filter);
|
||||||
|
|
||||||
this.timeDateOrTZChangeReceiver = new TimeDateOrTZChangeReceiver();
|
filter = new IntentFilter();
|
||||||
this.timeDateOrTZChangeReceiver.registerBroadcasts(this);
|
filter.addAction(Intent.ACTION_TIME_CHANGED);
|
||||||
|
filter.addAction(Intent.ACTION_DATE_CHANGED);
|
||||||
|
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
|
||||||
|
registerReceiver(new TimeDateOrTZChangeReceiver(), filter);
|
||||||
|
|
||||||
IntentFilter intentFilter = new IntentFilter();
|
filter = new IntentFilter();
|
||||||
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||||
intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
|
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
|
||||||
intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
|
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
|
||||||
registerReceiver(new NetworkChangeReceiver(), intentFilter);
|
registerReceiver(new NetworkChangeReceiver(), filter);
|
||||||
registerReceiver(new ChargingStateReceiver(), new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
|
||||||
|
filter = new IntentFilter();
|
||||||
|
filter.addAction(Intent.ACTION_POWER_CONNECTED);
|
||||||
|
filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
|
||||||
|
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
||||||
|
registerReceiver(new ChargingStateReceiver(), filter);
|
||||||
|
|
||||||
|
filter = new IntentFilter();
|
||||||
|
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
|
||||||
|
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
|
||||||
|
registerReceiver(new BTReceiver(), filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
|
@ -421,11 +279,7 @@ public class MainApp extends DaggerApplication {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTerminate() {
|
public void onTerminate() {
|
||||||
|
|
||||||
aapsLogger.debug(LTag.CORE, "onTerminate");
|
aapsLogger.debug(LTag.CORE, "onTerminate");
|
||||||
|
|
||||||
if (timeDateOrTZChangeReceiver != null)
|
|
||||||
unregisterReceiver(timeDateOrTZChangeReceiver);
|
|
||||||
unregisterActivityLifecycleCallbacks(activityMonitor);
|
unregisterActivityLifecycleCallbacks(activityMonitor);
|
||||||
keepAliveManager.cancelAlarm(this);
|
keepAliveManager.cancelAlarm(this);
|
||||||
super.onTerminate();
|
super.onTerminate();
|
||||||
|
|
|
@ -52,6 +52,7 @@ import info.nightscout.androidaps.plugins.source.PoctechPlugin
|
||||||
import info.nightscout.androidaps.plugins.source.TomatoPlugin
|
import info.nightscout.androidaps.plugins.source.TomatoPlugin
|
||||||
import info.nightscout.androidaps.utils.OKDialog.show
|
import info.nightscout.androidaps.utils.OKDialog.show
|
||||||
import info.nightscout.androidaps.utils.SafeParse
|
import info.nightscout.androidaps.utils.SafeParse
|
||||||
|
import info.nightscout.androidaps.utils.protection.PasswordCheck
|
||||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
@ -98,6 +99,8 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
||||||
@Inject lateinit var wearPlugin: WearPlugin
|
@Inject lateinit var wearPlugin: WearPlugin
|
||||||
@Inject lateinit var maintenancePlugin: MaintenancePlugin
|
@Inject lateinit var maintenancePlugin: MaintenancePlugin
|
||||||
|
|
||||||
|
@Inject lateinit var passwordCheck: PasswordCheck
|
||||||
|
|
||||||
@Inject lateinit var androidInjector: DispatchingAndroidInjector<Any>
|
@Inject lateinit var androidInjector: DispatchingAndroidInjector<Any>
|
||||||
|
|
||||||
override fun androidInjector(): AndroidInjector<Any> = androidInjector
|
override fun androidInjector(): AndroidInjector<Any> = androidInjector
|
||||||
|
@ -185,7 +188,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
||||||
addPreferencesFromResource(R.xml.pref_datachoices, rootKey)
|
addPreferencesFromResource(R.xml.pref_datachoices, rootKey)
|
||||||
addPreferencesFromResourceIfEnabled(maintenancePlugin, rootKey)
|
addPreferencesFromResourceIfEnabled(maintenancePlugin, rootKey)
|
||||||
}
|
}
|
||||||
initSummary(preferenceScreen)
|
initSummary(preferenceScreen, pluginId != -1)
|
||||||
for (plugin in pluginStore.plugins) {
|
for (plugin in pluginStore.plugins) {
|
||||||
plugin.preprocessPreferences(this)
|
plugin.preprocessPreferences(this)
|
||||||
}
|
}
|
||||||
|
@ -254,19 +257,19 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
||||||
// Preferences
|
// Preferences
|
||||||
if (pref.getKey() == resourceHelper.gs(R.string.key_settings_protection)) {
|
if (pref.getKey() == resourceHelper.gs(R.string.key_settings_protection)) {
|
||||||
val pass: Preference? = findPreference(resourceHelper.gs(R.string.key_settings_password))
|
val pass: Preference? = findPreference(resourceHelper.gs(R.string.key_settings_password))
|
||||||
if (pass != null) pass.isEnabled = pref.value == ProtectionCheck.ProtectionType.PASSWORD.ordinal.toString()
|
if (pass != null) pass.isEnabled = pref.value == ProtectionCheck.ProtectionType.CUSTOM_PASSWORD.ordinal.toString()
|
||||||
}
|
}
|
||||||
// Application
|
// Application
|
||||||
// Application
|
// Application
|
||||||
if (pref.getKey() == resourceHelper.gs(R.string.key_application_protection)) {
|
if (pref.getKey() == resourceHelper.gs(R.string.key_application_protection)) {
|
||||||
val pass: Preference? = findPreference(resourceHelper.gs(R.string.key_application_password))
|
val pass: Preference? = findPreference(resourceHelper.gs(R.string.key_application_password))
|
||||||
if (pass != null) pass.isEnabled = pref.value == ProtectionCheck.ProtectionType.PASSWORD.ordinal.toString()
|
if (pass != null) pass.isEnabled = pref.value == ProtectionCheck.ProtectionType.CUSTOM_PASSWORD.ordinal.toString()
|
||||||
}
|
}
|
||||||
// Bolus
|
// Bolus
|
||||||
// Bolus
|
// Bolus
|
||||||
if (pref.getKey() == resourceHelper.gs(R.string.key_bolus_protection)) {
|
if (pref.getKey() == resourceHelper.gs(R.string.key_bolus_protection)) {
|
||||||
val pass: Preference? = findPreference(resourceHelper.gs(R.string.key_bolus_password))
|
val pass: Preference? = findPreference(resourceHelper.gs(R.string.key_bolus_password))
|
||||||
if (pass != null) pass.isEnabled = pref.value == ProtectionCheck.ProtectionType.PASSWORD.ordinal.toString()
|
if (pass != null) pass.isEnabled = pref.value == ProtectionCheck.ProtectionType.CUSTOM_PASSWORD.ordinal.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pref is EditTextPreference) {
|
if (pref is EditTextPreference) {
|
||||||
|
@ -281,17 +284,66 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val hmacPasswords = arrayOf(
|
||||||
|
resourceHelper.gs(R.string.key_bolus_password),
|
||||||
|
resourceHelper.gs(R.string.key_master_password),
|
||||||
|
resourceHelper.gs(R.string.key_application_password),
|
||||||
|
resourceHelper.gs(R.string.key_settings_password)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (pref is Preference) {
|
||||||
|
if ((pref.key != null) && (hmacPasswords.contains(pref.key))) {
|
||||||
|
if (sp.getString(pref.key, "").startsWith("hmac:")) {
|
||||||
|
pref.summary = "******"
|
||||||
|
} else {
|
||||||
|
pref.summary = resourceHelper.gs(R.string.password_not_set)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
pref?.let { adjustUnitDependentPrefs(it) }
|
pref?.let { adjustUnitDependentPrefs(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initSummary(p: Preference) {
|
private fun initSummary(p: Preference, isSinglePreference: Boolean) {
|
||||||
p.isIconSpaceReserved = false // remove extra spacing on left after migration to androidx
|
p.isIconSpaceReserved = false // remove extra spacing on left after migration to androidx
|
||||||
|
// expand single plugin preference by default
|
||||||
|
if (p is PreferenceScreen && isSinglePreference) {
|
||||||
|
if (p.size > 0 && p.getPreference(0) is PreferenceCategory)
|
||||||
|
(p.getPreference(0) as PreferenceCategory).initialExpandedChildrenCount = Int.MAX_VALUE
|
||||||
|
}
|
||||||
if (p is PreferenceGroup) {
|
if (p is PreferenceGroup) {
|
||||||
for (i in 0 until p.preferenceCount) {
|
for (i in 0 until p.preferenceCount) {
|
||||||
initSummary(p.getPreference(i))
|
initSummary(p.getPreference(i), isSinglePreference)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
updatePrefSummary(p)
|
updatePrefSummary(p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We use Preference and custom editor instead of EditTextPreference
|
||||||
|
// to hash password while it is saved and never have to show it, even hashed
|
||||||
|
|
||||||
|
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
|
||||||
|
context?.let { context ->
|
||||||
|
if (preference != null) {
|
||||||
|
if (preference.key == resourceHelper.gs(R.string.key_master_password)) {
|
||||||
|
passwordCheck.setPassword(context, R.string.master_password, R.string.key_master_password)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (preference.key == resourceHelper.gs(R.string.key_settings_password)) {
|
||||||
|
passwordCheck.setPassword(context, R.string.settings_password, R.string.key_settings_password)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (preference.key == resourceHelper.gs(R.string.key_bolus_password)) {
|
||||||
|
passwordCheck.setPassword(context, R.string.bolus_password, R.string.key_bolus_password)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (preference.key == resourceHelper.gs(R.string.key_application_password)) {
|
||||||
|
passwordCheck.setPassword(context, R.string.application_password, R.string.key_application_password)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onPreferenceTreeClick(preference)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -10,8 +10,8 @@ import info.nightscout.androidaps.utils.LocaleHelper
|
||||||
open class NoSplashAppCompatActivity : DaggerAppCompatActivity() {
|
open class NoSplashAppCompatActivity : DaggerAppCompatActivity() {
|
||||||
|
|
||||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
setTheme(R.style.AppTheme_NoActionBar)
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
setTheme(R.style.AppTheme_NoActionBar)
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun attachBaseContext(newBase: Context) {
|
public override fun attachBaseContext(newBase: Context) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package info.nightscout.androidaps.data;
|
||||||
|
|
||||||
import androidx.collection.LongSparseArray;
|
import androidx.collection.LongSparseArray;
|
||||||
|
|
||||||
|
import org.joda.time.DateTime;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
@ -607,13 +608,15 @@ public class Profile {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int secondsFromMidnight() {
|
public static int secondsFromMidnight() {
|
||||||
long passed = DateUtil.now() - MidnightTime.calc();
|
// long passed = DateUtil.now() - MidnightTime.calc();
|
||||||
|
long passed = new DateTime().getMillisOfDay();
|
||||||
return (int) (passed / 1000);
|
return (int) (passed / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int secondsFromMidnight(long date) {
|
public static int secondsFromMidnight(long date) {
|
||||||
long midnight = MidnightTime.calc(date);
|
//long midnight = MidnightTime.calc(date);
|
||||||
long passed = date - midnight;
|
//long passed = date - midnight;
|
||||||
|
long passed = new DateTime(date).getMillisOfDay();
|
||||||
return (int) (passed / 1000);
|
return (int) (passed / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,7 @@ interface AppComponent : AndroidInjector<MainApp> {
|
||||||
fun injectTrigger(triggerAutosensValue: TriggerAutosensValue)
|
fun injectTrigger(triggerAutosensValue: TriggerAutosensValue)
|
||||||
fun injectTrigger(triggerBg: TriggerBg)
|
fun injectTrigger(triggerBg: TriggerBg)
|
||||||
fun injectTrigger(triggerBolusAgo: TriggerBolusAgo)
|
fun injectTrigger(triggerBolusAgo: TriggerBolusAgo)
|
||||||
|
fun injectTrigger(triggerBTDevice: TriggerBTDevice)
|
||||||
fun injectTrigger(triggerCOB: TriggerCOB)
|
fun injectTrigger(triggerCOB: TriggerCOB)
|
||||||
fun injectTrigger(triggerConnector: TriggerConnector)
|
fun injectTrigger(triggerConnector: TriggerConnector)
|
||||||
fun injectTrigger(triggerDelta: TriggerDelta)
|
fun injectTrigger(triggerDelta: TriggerDelta)
|
||||||
|
@ -127,8 +128,10 @@ interface AppComponent : AndroidInjector<MainApp> {
|
||||||
fun injectElement(inputButton: InputButton)
|
fun injectElement(inputButton: InputButton)
|
||||||
fun injectElement(comparator: Comparator)
|
fun injectElement(comparator: Comparator)
|
||||||
fun injectElement(comparatorExists: ComparatorExists)
|
fun injectElement(comparatorExists: ComparatorExists)
|
||||||
|
fun injectElement(comparatorConnect: ComparatorConnect)
|
||||||
fun injectElement(inputDateTime: InputDateTime)
|
fun injectElement(inputDateTime: InputDateTime)
|
||||||
fun injectElement(inputDelta: InputDelta)
|
fun injectElement(inputDelta: InputDelta)
|
||||||
|
fun injectElement(inputDropdownMenu: InputDropdownMenu)
|
||||||
fun injectElement(inputDouble: InputDouble)
|
fun injectElement(inputDouble: InputDouble)
|
||||||
fun injectElement(inputDuration: InputDuration)
|
fun injectElement(inputDuration: InputDuration)
|
||||||
fun injectElement(inputInsulin: InputInsulin)
|
fun injectElement(inputInsulin: InputInsulin)
|
||||||
|
|
|
@ -3,10 +3,12 @@ package info.nightscout.androidaps.dependencyInjection
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import dagger.Binds
|
import dagger.Binds
|
||||||
|
import dagger.Lazy
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.android.ContributesAndroidInjector
|
import dagger.android.ContributesAndroidInjector
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.Config
|
||||||
import info.nightscout.androidaps.MainApp
|
import info.nightscout.androidaps.MainApp
|
||||||
import info.nightscout.androidaps.data.Profile
|
import info.nightscout.androidaps.data.Profile
|
||||||
import info.nightscout.androidaps.data.ProfileStore
|
import info.nightscout.androidaps.data.ProfileStore
|
||||||
|
@ -15,6 +17,7 @@ import info.nightscout.androidaps.db.BgReading
|
||||||
import info.nightscout.androidaps.db.ProfileSwitch
|
import info.nightscout.androidaps.db.ProfileSwitch
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
import info.nightscout.androidaps.interfaces.CommandQueueProvider
|
||||||
|
import info.nightscout.androidaps.interfaces.PluginBase
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.AAPSLoggerProduction
|
import info.nightscout.androidaps.logging.AAPSLoggerProduction
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult
|
import info.nightscout.androidaps.plugins.aps.loop.APSResult
|
||||||
|
@ -23,7 +26,6 @@ import info.nightscout.androidaps.plugins.aps.openAPSMA.DetermineBasalResultMA
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSMA.LoggerCallback
|
import info.nightscout.androidaps.plugins.aps.openAPSMA.LoggerCallback
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalAdapterSMBJS
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.DetermineBasalResultSMB
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.PluginStore
|
import info.nightscout.androidaps.plugins.configBuilder.PluginStore
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction
|
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctionImplementation
|
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctionImplementation
|
||||||
|
@ -33,6 +35,9 @@ import info.nightscout.androidaps.plugins.general.automation.actions.*
|
||||||
import info.nightscout.androidaps.plugins.general.automation.elements.*
|
import info.nightscout.androidaps.plugins.general.automation.elements.*
|
||||||
import info.nightscout.androidaps.plugins.general.automation.triggers.*
|
import info.nightscout.androidaps.plugins.general.automation.triggers.*
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
|
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
|
||||||
|
import info.nightscout.androidaps.plugins.general.maintenance.ImportExportPrefs
|
||||||
|
import info.nightscout.androidaps.plugins.general.maintenance.formats.ClassicPrefsFormat
|
||||||
|
import info.nightscout.androidaps.plugins.general.maintenance.formats.EncryptedPrefsFormat
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction
|
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction
|
||||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.AuthRequest
|
import info.nightscout.androidaps.plugins.general.smsCommunicator.AuthRequest
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensData
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensData
|
||||||
|
@ -42,7 +47,6 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobThread
|
||||||
import info.nightscout.androidaps.plugins.treatments.Treatment
|
import info.nightscout.androidaps.plugins.treatments.Treatment
|
||||||
import info.nightscout.androidaps.queue.CommandQueue
|
import info.nightscout.androidaps.queue.CommandQueue
|
||||||
import info.nightscout.androidaps.queue.commands.*
|
import info.nightscout.androidaps.queue.commands.*
|
||||||
import info.nightscout.androidaps.setupwizard.SWDefinition
|
|
||||||
import info.nightscout.androidaps.setupwizard.SWEventListener
|
import info.nightscout.androidaps.setupwizard.SWEventListener
|
||||||
import info.nightscout.androidaps.setupwizard.SWScreen
|
import info.nightscout.androidaps.setupwizard.SWScreen
|
||||||
import info.nightscout.androidaps.setupwizard.elements.*
|
import info.nightscout.androidaps.setupwizard.elements.*
|
||||||
|
@ -51,11 +55,13 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelperImplementation
|
import info.nightscout.androidaps.utils.resources.ResourceHelperImplementation
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SPImplementation
|
import info.nightscout.androidaps.utils.sharedPreferences.SPImplementation
|
||||||
|
import info.nightscout.androidaps.utils.storage.FileStorage
|
||||||
|
import info.nightscout.androidaps.utils.storage.Storage
|
||||||
import info.nightscout.androidaps.utils.wizard.BolusWizard
|
import info.nightscout.androidaps.utils.wizard.BolusWizard
|
||||||
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry
|
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Module(includes = [AppModule.AppBindings::class])
|
@Module(includes = [AppModule.AppBindings::class, PluginsModule::class])
|
||||||
open class AppModule {
|
open class AppModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -88,6 +94,24 @@ open class AppModule {
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
fun providesPlugins(@PluginsModule.AllConfigs allConfigs: Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>,
|
||||||
|
@PluginsModule.PumpDriver pumpDrivers: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>,
|
||||||
|
@PluginsModule.NotNSClient notNsClient: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>,
|
||||||
|
@PluginsModule.APS aps: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>): List<@JvmSuppressWildcards PluginBase> {
|
||||||
|
val plugins = allConfigs.toMutableMap()
|
||||||
|
if (Config.PUMPDRIVERS) plugins += pumpDrivers.get()
|
||||||
|
if (Config.APS) plugins += aps.get()
|
||||||
|
if (!Config.NSCLIENT) plugins += notNsClient.get()
|
||||||
|
return plugins.toList().sortedBy { it.first }.map { it.second }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideStorage(): Storage {
|
||||||
|
return FileStorage()
|
||||||
|
}
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
interface AppBindings {
|
interface AppBindings {
|
||||||
|
|
||||||
|
@ -156,6 +180,7 @@ open class AppModule {
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
fun triggerPumpLastConnectionInjector(): TriggerPumpLastConnection
|
fun triggerPumpLastConnectionInjector(): TriggerPumpLastConnection
|
||||||
|
|
||||||
|
@ContributesAndroidInjector fun triggerBTDeviceInjector(): TriggerBTDevice
|
||||||
@ContributesAndroidInjector fun triggerRecurringTimeInjector(): TriggerRecurringTime
|
@ContributesAndroidInjector fun triggerRecurringTimeInjector(): TriggerRecurringTime
|
||||||
@ContributesAndroidInjector fun triggerTempTargetInjector(): TriggerTempTarget
|
@ContributesAndroidInjector fun triggerTempTargetInjector(): TriggerTempTarget
|
||||||
@ContributesAndroidInjector fun triggerTime(): TriggerTime
|
@ContributesAndroidInjector fun triggerTime(): TriggerTime
|
||||||
|
@ -182,10 +207,12 @@ open class AppModule {
|
||||||
@ContributesAndroidInjector fun inputBgInjector(): InputBg
|
@ContributesAndroidInjector fun inputBgInjector(): InputBg
|
||||||
@ContributesAndroidInjector fun inputButtonInjector(): InputButton
|
@ContributesAndroidInjector fun inputButtonInjector(): InputButton
|
||||||
@ContributesAndroidInjector fun comparatorInjector(): Comparator
|
@ContributesAndroidInjector fun comparatorInjector(): Comparator
|
||||||
|
@ContributesAndroidInjector fun comparatorConnectInjector(): ComparatorConnect
|
||||||
@ContributesAndroidInjector fun comparatorExistsInjector(): ComparatorExists
|
@ContributesAndroidInjector fun comparatorExistsInjector(): ComparatorExists
|
||||||
@ContributesAndroidInjector fun inputDateTimeInjector(): InputDateTime
|
@ContributesAndroidInjector fun inputDateTimeInjector(): InputDateTime
|
||||||
@ContributesAndroidInjector fun inputDeltaInjector(): InputDelta
|
@ContributesAndroidInjector fun inputDeltaInjector(): InputDelta
|
||||||
@ContributesAndroidInjector fun inputDoubleInjector(): InputDouble
|
@ContributesAndroidInjector fun inputDoubleInjector(): InputDouble
|
||||||
|
@ContributesAndroidInjector fun inputDropdownMenuInjector(): InputDropdownMenu
|
||||||
@ContributesAndroidInjector fun inputDurationInjector(): InputDuration
|
@ContributesAndroidInjector fun inputDurationInjector(): InputDuration
|
||||||
@ContributesAndroidInjector fun inputInsulinInjector(): InputInsulin
|
@ContributesAndroidInjector fun inputInsulinInjector(): InputInsulin
|
||||||
@ContributesAndroidInjector fun inputLocationModeInjector(): InputLocationMode
|
@ContributesAndroidInjector fun inputLocationModeInjector(): InputLocationMode
|
||||||
|
@ -234,6 +261,10 @@ open class AppModule {
|
||||||
|
|
||||||
@ContributesAndroidInjector fun graphDataInjector(): GraphData
|
@ContributesAndroidInjector fun graphDataInjector(): GraphData
|
||||||
|
|
||||||
|
@ContributesAndroidInjector fun importExportPrefsInjector(): ImportExportPrefs
|
||||||
|
@ContributesAndroidInjector fun encryptedPrefsFormatInjector(): EncryptedPrefsFormat
|
||||||
|
@ContributesAndroidInjector fun classicPrefsFormatInjector(): ClassicPrefsFormat
|
||||||
|
|
||||||
@Binds fun bindContext(mainApp: MainApp): Context
|
@Binds fun bindContext(mainApp: MainApp): Context
|
||||||
@Binds fun bindInjector(mainApp: MainApp): HasAndroidInjector
|
@Binds fun bindInjector(mainApp: MainApp): HasAndroidInjector
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import info.nightscout.androidaps.plugins.general.overview.OverviewFragment
|
||||||
import info.nightscout.androidaps.plugins.general.overview.dialogs.EditQuickWizardDialog
|
import info.nightscout.androidaps.plugins.general.overview.dialogs.EditQuickWizardDialog
|
||||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorFragment
|
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorFragment
|
||||||
import info.nightscout.androidaps.plugins.general.tidepool.TidepoolFragment
|
import info.nightscout.androidaps.plugins.general.tidepool.TidepoolFragment
|
||||||
|
import info.nightscout.androidaps.plugins.general.wear.WearFragment
|
||||||
import info.nightscout.androidaps.plugins.insulin.InsulinFragment
|
import info.nightscout.androidaps.plugins.insulin.InsulinFragment
|
||||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfileFragment
|
import info.nightscout.androidaps.plugins.profile.local.LocalProfileFragment
|
||||||
import info.nightscout.androidaps.plugins.profile.ns.NSProfileFragment
|
import info.nightscout.androidaps.plugins.profile.ns.NSProfileFragment
|
||||||
|
@ -39,6 +40,7 @@ import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpFragment
|
||||||
import info.nightscout.androidaps.plugins.source.BGSourceFragment
|
import info.nightscout.androidaps.plugins.source.BGSourceFragment
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsFragment
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsFragment
|
||||||
import info.nightscout.androidaps.plugins.treatments.fragments.*
|
import info.nightscout.androidaps.plugins.treatments.fragments.*
|
||||||
|
import info.nightscout.androidaps.utils.protection.PasswordCheck
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
|
@ -71,6 +73,7 @@ abstract class FragmentsModule {
|
||||||
@ContributesAndroidInjector abstract fun contributesNSProfileFragment(): NSProfileFragment
|
@ContributesAndroidInjector abstract fun contributesNSProfileFragment(): NSProfileFragment
|
||||||
@ContributesAndroidInjector abstract fun contributesNSClientFragment(): NSClientFragment
|
@ContributesAndroidInjector abstract fun contributesNSClientFragment(): NSClientFragment
|
||||||
@ContributesAndroidInjector abstract fun contributesSmsCommunicatorFragment(): SmsCommunicatorFragment
|
@ContributesAndroidInjector abstract fun contributesSmsCommunicatorFragment(): SmsCommunicatorFragment
|
||||||
|
@ContributesAndroidInjector abstract fun contributesWearFragment(): WearFragment
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment
|
@ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment
|
||||||
@ContributesAndroidInjector abstract fun contributesTreatmentsFragment(): TreatmentsFragment
|
@ContributesAndroidInjector abstract fun contributesTreatmentsFragment(): TreatmentsFragment
|
||||||
|
@ -110,4 +113,6 @@ abstract class FragmentsModule {
|
||||||
@ContributesAndroidInjector abstract fun contributesTreatmentDialog(): TreatmentDialog
|
@ContributesAndroidInjector abstract fun contributesTreatmentDialog(): TreatmentDialog
|
||||||
@ContributesAndroidInjector abstract fun contributesWizardDialog(): WizardDialog
|
@ContributesAndroidInjector abstract fun contributesWizardDialog(): WizardDialog
|
||||||
@ContributesAndroidInjector abstract fun contributesWizardInfoDialog(): WizardInfoDialog
|
@ContributesAndroidInjector abstract fun contributesWizardInfoDialog(): WizardInfoDialog
|
||||||
|
|
||||||
|
@ContributesAndroidInjector abstract fun contributesPasswordCheck(): PasswordCheck
|
||||||
}
|
}
|
|
@ -0,0 +1,379 @@
|
||||||
|
package info.nightscout.androidaps.dependencyInjection
|
||||||
|
|
||||||
|
import dagger.Binds
|
||||||
|
import dagger.Lazy
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.multibindings.IntKey
|
||||||
|
import dagger.multibindings.IntoMap
|
||||||
|
import dagger.multibindings.IntoSet
|
||||||
|
import info.nightscout.androidaps.Config
|
||||||
|
import info.nightscout.androidaps.interfaces.PluginBase
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.aps.openAPSAMA.OpenAPSAMAPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.aps.openAPSMA.OpenAPSMAPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.OpenAPSSMBPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.constraints.dstHelper.DstHelperPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.constraints.signatureVerifier.SignatureVerifierPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.constraints.storage.StorageConstraintPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.general.actions.ActionsPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.general.careportal.CareportalPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.general.dataBroadcaster.DataBroadcastPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.general.food.FoodPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.general.maintenance.MaintenancePlugin
|
||||||
|
import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.general.persistentNotification.PersistentNotificationPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.general.wear.WearPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.general.xdripStatusline.StatusLinePlugin
|
||||||
|
import info.nightscout.androidaps.plugins.insulin.InsulinOrefFreePeakPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.insulin.InsulinOrefRapidActingPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.insulin.InsulinOrefUltraRapidActingPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin
|
||||||
|
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin
|
||||||
|
import info.nightscout.androidaps.plugins.pump.combo.ComboPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.pump.danaR.DanaRPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.pump.danaRS.DanaRSPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.pump.danaRv2.DanaRv2Plugin
|
||||||
|
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.pump.mdi.MDIPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.sensitivity.SensitivityAAPSPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin
|
||||||
|
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin
|
||||||
|
import info.nightscout.androidaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
|
||||||
|
import info.nightscout.androidaps.plugins.source.*
|
||||||
|
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
|
||||||
|
import javax.inject.Qualifier
|
||||||
|
|
||||||
|
@Module
|
||||||
|
abstract class PluginsModule {
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(0)
|
||||||
|
abstract fun bindOverviewPlugin(plugin: OverviewPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(10)
|
||||||
|
abstract fun bindIobCobCalculatorPlugin(plugin: IobCobCalculatorPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@NotNSClient
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(20)
|
||||||
|
abstract fun bindActionsPlugin(plugin: ActionsPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(30)
|
||||||
|
abstract fun bindInsulinOrefRapidActingPlugin(plugin: InsulinOrefRapidActingPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(40)
|
||||||
|
abstract fun bindInsulinOrefUltraRapidActingPlugin(plugin: InsulinOrefUltraRapidActingPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(50)
|
||||||
|
abstract fun bindInsulinOrefFreePeakPlugin(plugin: InsulinOrefFreePeakPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(60)
|
||||||
|
abstract fun bindSensitivityOref0Plugin(plugin: SensitivityOref0Plugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(70)
|
||||||
|
abstract fun bindSensitivityAAPSPlugin(plugin: SensitivityAAPSPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(80)
|
||||||
|
abstract fun bindSensitivityWeightedAveragePlugin(plugin: SensitivityWeightedAveragePlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(90)
|
||||||
|
abstract fun bindSensitivityOref1Plugin(plugin: SensitivityOref1Plugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@PumpDriver
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(100)
|
||||||
|
abstract fun bindDanaRPlugin(plugin: DanaRPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@PumpDriver
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(110)
|
||||||
|
abstract fun bindDanaRKoreanPlugin(plugin: DanaRKoreanPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@PumpDriver
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(120)
|
||||||
|
abstract fun bindDanaRv2Plugin(plugin: DanaRv2Plugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@PumpDriver
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(130)
|
||||||
|
abstract fun bindDanaRSPlugin(plugin: DanaRSPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@PumpDriver
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(140)
|
||||||
|
abstract fun bindLocalInsightPlugin(plugin: LocalInsightPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@PumpDriver
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(150)
|
||||||
|
abstract fun bindComboPlugin(plugin: ComboPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@PumpDriver
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(160)
|
||||||
|
abstract fun bindMedtronicPumpPlugin(plugin: MedtronicPumpPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@NotNSClient
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(170)
|
||||||
|
abstract fun bindMDIPlugin(plugin: MDIPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(180)
|
||||||
|
abstract fun bindVirtualPumpPlugin(plugin: VirtualPumpPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@NotNSClient
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(190)
|
||||||
|
abstract fun bindCareportalPlugin(plugin: CareportalPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@APS
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(200)
|
||||||
|
abstract fun bindLoopPlugin(plugin: LoopPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@APS
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(210)
|
||||||
|
abstract fun bindOpenAPSMAPlugin(plugin: OpenAPSMAPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@APS
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(220)
|
||||||
|
abstract fun bindOpenAPSAMAPlugin(plugin: OpenAPSAMAPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@APS
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(230)
|
||||||
|
abstract fun bindOpenAPSSMBPlugin(plugin: OpenAPSSMBPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(240)
|
||||||
|
abstract fun bindNSProfilePlugin(plugin: NSProfilePlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@NotNSClient
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(250)
|
||||||
|
abstract fun bindLocalProfilePlugin(plugin: LocalProfilePlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(255)
|
||||||
|
abstract fun bindAutomationPlugin(plugin: AutomationPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(260)
|
||||||
|
abstract fun bindTreatmentsPlugin(plugin: TreatmentsPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@NotNSClient
|
||||||
|
@IntoSet
|
||||||
|
abstract fun bindSafetyPlugin(plugin: SafetyPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@NotNSClient
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(270)
|
||||||
|
abstract fun bindVersionCheckerPlugin(plugin: VersionCheckerPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@NotNSClient
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(280)
|
||||||
|
abstract fun bindSmsCommunicatorPlugin(plugin: SmsCommunicatorPlugin): PluginBase
|
||||||
|
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@APS
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(290)
|
||||||
|
abstract fun bindStorageConstraintPlugin(plugin: StorageConstraintPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@APS
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(300)
|
||||||
|
abstract fun bindSignatureVerifierPlugin(plugin: SignatureVerifierPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@APS
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(310)
|
||||||
|
abstract fun bindObjectivesPlugin(plugin: ObjectivesPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(320)
|
||||||
|
abstract fun bindFoodPlugin(plugin: FoodPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(330)
|
||||||
|
abstract fun bindWearPlugin(plugin: WearPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(340)
|
||||||
|
abstract fun bindStatusLinePlugin(plugin: StatusLinePlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(350)
|
||||||
|
abstract fun bindPersistentNotificationPlugin(plugin: PersistentNotificationPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(360)
|
||||||
|
abstract fun bindNSClientPlugin(plugin: NSClientPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(370)
|
||||||
|
abstract fun bindMaintenancePlugin(plugin: MaintenancePlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(380)
|
||||||
|
abstract fun bindDstHelperPlugin(plugin: DstHelperPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(390)
|
||||||
|
abstract fun bindDataBroadcastPlugin(plugin: DataBroadcastPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(400)
|
||||||
|
abstract fun bindXdripPlugin(plugin: XdripPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(410)
|
||||||
|
abstract fun bindNSClientSourcePlugin(plugin: NSClientSourcePlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(420)
|
||||||
|
abstract fun bindMM640gPlugin(plugin: MM640gPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(430)
|
||||||
|
abstract fun bindGlimpPlugin(plugin: GlimpPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(440)
|
||||||
|
abstract fun bindDexcomPlugin(plugin: DexcomPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(450)
|
||||||
|
abstract fun bindPoctechPlugin(plugin: PoctechPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(460)
|
||||||
|
abstract fun bindTomatoPlugin(plugin: TomatoPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(470)
|
||||||
|
abstract fun bindRandomBgPlugin(plugin: RandomBgPlugin): PluginBase
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@AllConfigs
|
||||||
|
@IntoMap
|
||||||
|
@IntKey(480)
|
||||||
|
abstract fun bindConfigBuilderPlugin(plugin: ConfigBuilderPlugin): PluginBase
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
annotation class AllConfigs
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
annotation class PumpDriver
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
annotation class NotNSClient
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
annotation class APS
|
||||||
|
|
||||||
|
}
|
|
@ -3,14 +3,17 @@ package info.nightscout.androidaps.dependencyInjection
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.android.ContributesAndroidInjector
|
import dagger.android.ContributesAndroidInjector
|
||||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkBluetoothStateReceiver
|
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkBluetoothStateReceiver
|
||||||
import info.nightscout.androidaps.receivers.KeepAliveReceiver
|
import info.nightscout.androidaps.receivers.*
|
||||||
import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver
|
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
abstract class ReceiversModule {
|
abstract class ReceiversModule {
|
||||||
|
|
||||||
|
@ContributesAndroidInjector abstract fun contributesBTReceiver(): BTReceiver
|
||||||
|
@ContributesAndroidInjector abstract fun contributesChargingStateReceiver(): ChargingStateReceiver
|
||||||
|
@ContributesAndroidInjector abstract fun contributesDataReceiver(): DataReceiver
|
||||||
@ContributesAndroidInjector abstract fun contributesKeepAliveReceiver(): KeepAliveReceiver
|
@ContributesAndroidInjector abstract fun contributesKeepAliveReceiver(): KeepAliveReceiver
|
||||||
@ContributesAndroidInjector abstract fun contributesTimeDateOrTZChangeReceiver(): TimeDateOrTZChangeReceiver
|
@ContributesAndroidInjector abstract fun contributesNetworkChangeReceiver(): NetworkChangeReceiver
|
||||||
@ContributesAndroidInjector abstract fun contributesRileyLinkBluetoothStateReceiver(): RileyLinkBluetoothStateReceiver
|
@ContributesAndroidInjector abstract fun contributesRileyLinkBluetoothStateReceiver(): RileyLinkBluetoothStateReceiver
|
||||||
|
@ContributesAndroidInjector abstract fun contributesTimeDateOrTZChangeReceiver(): TimeDateOrTZChangeReceiver
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@ package info.nightscout.androidaps.dependencyInjection
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.android.ContributesAndroidInjector
|
import dagger.android.ContributesAndroidInjector
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService
|
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.notifications.DismissNotificationService
|
||||||
import info.nightscout.androidaps.plugins.general.persistentNotification.DummyService
|
import info.nightscout.androidaps.plugins.general.persistentNotification.DummyService
|
||||||
import info.nightscout.androidaps.plugins.general.wear.wearintegration.WatchUpdaterService
|
import info.nightscout.androidaps.plugins.general.wear.wearintegration.WatchUpdaterService
|
||||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkService
|
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkService
|
||||||
|
@ -25,6 +26,7 @@ abstract class ServicesModule {
|
||||||
@ContributesAndroidInjector abstract fun contributesAbstractDanaRExecutionService(): AbstractDanaRExecutionService
|
@ContributesAndroidInjector abstract fun contributesAbstractDanaRExecutionService(): AbstractDanaRExecutionService
|
||||||
@ContributesAndroidInjector abstract fun contributesAlarmSoundService(): AlarmSoundService
|
@ContributesAndroidInjector abstract fun contributesAlarmSoundService(): AlarmSoundService
|
||||||
@ContributesAndroidInjector abstract fun contributesDataService(): DataService
|
@ContributesAndroidInjector abstract fun contributesDataService(): DataService
|
||||||
|
@ContributesAndroidInjector abstract fun contributesDismissNotificationService(): DismissNotificationService
|
||||||
@ContributesAndroidInjector abstract fun contributesDummyService(): DummyService
|
@ContributesAndroidInjector abstract fun contributesDummyService(): DummyService
|
||||||
@ContributesAndroidInjector abstract fun contributesLocationService(): LocationService
|
@ContributesAndroidInjector abstract fun contributesLocationService(): LocationService
|
||||||
@ContributesAndroidInjector abstract fun contributesNSClientService(): NSClientService
|
@ContributesAndroidInjector abstract fun contributesNSClientService(): NSClientService
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package info.nightscout.androidaps.events
|
||||||
|
|
||||||
|
class EventBTChange constructor(val state: Change, val deviceName: String) : Event() {
|
||||||
|
enum class Change {
|
||||||
|
CONNECT,
|
||||||
|
DISCONNECT
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,9 +6,11 @@ class EventNetworkChange : Event() {
|
||||||
|
|
||||||
var mobileConnected = false
|
var mobileConnected = false
|
||||||
var wifiConnected = false
|
var wifiConnected = false
|
||||||
|
var vpnConnected = false
|
||||||
|
|
||||||
var ssid = ""
|
var ssid = ""
|
||||||
var roaming = false
|
var roaming = false
|
||||||
|
var metered = false
|
||||||
|
|
||||||
fun connectedSsid(): String {
|
fun connectedSsid(): String {
|
||||||
return StringUtils.removeSurroundingQuotes(ssid)
|
return StringUtils.removeSurroundingQuotes(ssid)
|
||||||
|
|
|
@ -15,17 +15,7 @@ class EventPreferenceChange : Event {
|
||||||
changedKey = resourceHelper.gs(resourceID)
|
changedKey = resourceHelper.gs(resourceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("use injected version")
|
|
||||||
constructor(resources: Resources, id: Int) {
|
|
||||||
changedKey == resources.getString(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isChanged(resourceHelper: ResourceHelper, id: Int): Boolean {
|
fun isChanged(resourceHelper: ResourceHelper, id: Int): Boolean {
|
||||||
return changedKey == resourceHelper.gs(id)
|
return changedKey == resourceHelper.gs(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("use injected version")
|
|
||||||
fun isChanged(resources: Resources, id: Int): Boolean {
|
|
||||||
return changedKey == resources.getString(id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -303,7 +303,7 @@ public class HistoryBrowseActivity extends NoSplashAppCompatActivity {
|
||||||
|
|
||||||
// add basal data
|
// add basal data
|
||||||
if (pump.getPumpDescription().isTempBasalCapable && showBasal) {
|
if (pump.getPumpDescription().isTempBasalCapable && showBasal) {
|
||||||
graphData.addBasals(fromTime, toTime, lowLine / graphData.maxY / 1.2d);
|
graphData.addBasals(fromTime, toTime, lowLine / graphData.getMaxY() / 1.2d);
|
||||||
}
|
}
|
||||||
|
|
||||||
// **** NOW line ****
|
// **** NOW line ****
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
package info.nightscout.androidaps.logging
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by adrian on 2019-12-27.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AAPSLoggerTest : AAPSLogger {
|
||||||
|
|
||||||
|
override fun debug(message: String) {
|
||||||
|
println("DEBUG: $message")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun debug(enable: Boolean, tag: LTag, message: String) {
|
||||||
|
println("DEBUG: " + message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun debug(tag: LTag, message: String) {
|
||||||
|
println("DEBUG: : " + tag.tag + " " + message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun debug(tag: LTag, format: String, vararg arguments: Any?) {
|
||||||
|
println("DEBUG: : " + tag.tag + " " + String.format(format, arguments))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun warn(tag: LTag, message: String) {
|
||||||
|
println("WARN: " + tag.tag + " " + message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun info(tag: LTag, message: String) {
|
||||||
|
println("INFO: " + tag.tag + " " + message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun info(tag: LTag, format: String, vararg arguments: Any?) {
|
||||||
|
println("INFO: : " + tag.tag + " " + String.format(format, arguments))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun error(tag: LTag, message: String) {
|
||||||
|
println("ERROR: " + tag.tag + " " + message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun error(message: String) {
|
||||||
|
println("ERROR: " + message)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun error(message: String, throwable: Throwable) {
|
||||||
|
println("ERROR: " + message + " " + throwable)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun error(format: String, vararg arguments: Any?) {
|
||||||
|
println("ERROR: : " + String.format(format, arguments))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun error(tag: LTag, message: String, throwable: Throwable) {
|
||||||
|
println("ERROR: " + tag.tag + " " + message + " " + throwable)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun error(tag: LTag, format: String, vararg arguments: Any?) {
|
||||||
|
println("ERROR: : " + tag.tag + " " + String.format(format, arguments))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,65 +1,25 @@
|
||||||
package info.nightscout.androidaps.logging
|
package info.nightscout.androidaps.logging
|
||||||
|
|
||||||
import info.nightscout.androidaps.utils.SP
|
import androidx.preference.PreferenceManager
|
||||||
|
import info.nightscout.androidaps.MainApp
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
object L {
|
object L {
|
||||||
private var logElements: MutableList<LogElement> = ArrayList()
|
private var logElements: MutableList<LogElement> = ArrayList()
|
||||||
|
|
||||||
const val CORE = "CORE"
|
const val CORE = "CORE"
|
||||||
const val AUTOSENS = "AUTOSENS"
|
|
||||||
const val AUTOMATION = "AUTOMATION"
|
|
||||||
const val EVENTS = "EVENTS"
|
|
||||||
const val GLUCOSE = "GLUCOSE"
|
|
||||||
const val BGSOURCE = "BGSOURCE"
|
const val BGSOURCE = "BGSOURCE"
|
||||||
const val OVERVIEW = "OVERVIEW"
|
|
||||||
const val NOTIFICATION = "NOTIFICATION"
|
|
||||||
const val DATASERVICE = "DATASERVICE"
|
const val DATASERVICE = "DATASERVICE"
|
||||||
const val DATABASE = "DATABASE"
|
const val DATABASE = "DATABASE"
|
||||||
const val DATAFOOD = "DATAFOOD"
|
const val DATAFOOD = "DATAFOOD"
|
||||||
const val DATATREATMENTS = "DATATREATMENTS"
|
const val DATATREATMENTS = "DATATREATMENTS"
|
||||||
const val NSCLIENT = "NSCLIENT"
|
const val NSCLIENT = "NSCLIENT"
|
||||||
const val TIDEPOOL = "TIDEPOOL"
|
|
||||||
const val CONSTRAINTS = "CONSTRAINTS"
|
|
||||||
const val PUMP = "PUMP"
|
const val PUMP = "PUMP"
|
||||||
const val PUMPQUEUE = "PUMPQUEUE"
|
|
||||||
const val PUMPCOMM = "PUMPCOMM"
|
const val PUMPCOMM = "PUMPCOMM"
|
||||||
const val PUMPBTCOMM = "PUMPBTCOMM"
|
const val PUMPBTCOMM = "PUMPBTCOMM"
|
||||||
const val APS = "APS"
|
|
||||||
const val PROFILE = "PROFILE"
|
|
||||||
const val CONFIGBUILDER = "CONFIGBUILDER"
|
|
||||||
const val UI = "UI"
|
|
||||||
const val LOCATION = "LOCATION"
|
|
||||||
const val SMS = "SMS"
|
|
||||||
const val WEAR = "WEAR"
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
logElements.add(LogElement(APS, defaultValue = true))
|
LTag.values().forEach { logElements.add(LogElement(it)) }
|
||||||
logElements.add(LogElement(AUTOMATION, defaultValue = true))
|
|
||||||
logElements.add(LogElement(AUTOSENS, defaultValue = false))
|
|
||||||
logElements.add(LogElement(BGSOURCE, defaultValue = true))
|
|
||||||
logElements.add(LogElement(GLUCOSE, defaultValue = false))
|
|
||||||
logElements.add(LogElement(CONFIGBUILDER, defaultValue = false))
|
|
||||||
logElements.add(LogElement(CONSTRAINTS, defaultValue = true))
|
|
||||||
logElements.add(LogElement(CORE, defaultValue = true))
|
|
||||||
logElements.add(LogElement(DATABASE, defaultValue = true))
|
|
||||||
logElements.add(LogElement(DATAFOOD, false))
|
|
||||||
logElements.add(LogElement(DATASERVICE, true))
|
|
||||||
logElements.add(LogElement(DATATREATMENTS, true))
|
|
||||||
logElements.add(LogElement(EVENTS, false, requiresRestart = true))
|
|
||||||
logElements.add(LogElement(LOCATION, true))
|
|
||||||
logElements.add(LogElement(NOTIFICATION, true))
|
|
||||||
logElements.add(LogElement(NSCLIENT, true))
|
|
||||||
logElements.add(LogElement(TIDEPOOL, true))
|
|
||||||
logElements.add(LogElement(OVERVIEW, true))
|
|
||||||
logElements.add(LogElement(PROFILE, true))
|
|
||||||
logElements.add(LogElement(PUMP, true))
|
|
||||||
logElements.add(LogElement(PUMPBTCOMM, false))
|
|
||||||
logElements.add(LogElement(PUMPCOMM, true))
|
|
||||||
logElements.add(LogElement(PUMPQUEUE, true))
|
|
||||||
logElements.add(LogElement(SMS, true))
|
|
||||||
logElements.add(LogElement(UI, true))
|
|
||||||
logElements.add(LogElement(WEAR, true))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findByName(name: String): LogElement {
|
private fun findByName(name: String): LogElement {
|
||||||
|
@ -90,17 +50,13 @@ object L {
|
||||||
var enabled: Boolean
|
var enabled: Boolean
|
||||||
private var requiresRestart = false
|
private var requiresRestart = false
|
||||||
|
|
||||||
internal constructor(name: String, defaultValue: Boolean) {
|
internal constructor(tag: LTag) {
|
||||||
this.name = name
|
this.name = tag.tag
|
||||||
this.defaultValue = defaultValue
|
this.defaultValue = tag.defaultValue
|
||||||
enabled = SP.getBoolean(getSPName(), defaultValue)
|
this.requiresRestart = tag.requiresRestart
|
||||||
}
|
//TODO: remove after getting rid of old logging style "if (L.isEnabled(...))"
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
internal constructor(name: String, defaultValue: Boolean, requiresRestart: Boolean) {
|
enabled = PreferenceManager.getDefaultSharedPreferences(MainApp.instance()).getBoolean(getSPName(), defaultValue)
|
||||||
this.name = name
|
|
||||||
this.defaultValue = defaultValue
|
|
||||||
this.requiresRestart = requiresRestart
|
|
||||||
enabled = SP.getBoolean(getSPName(), defaultValue)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal constructor(defaultValue: Boolean) {
|
internal constructor(defaultValue: Boolean) {
|
||||||
|
@ -113,40 +69,12 @@ object L {
|
||||||
|
|
||||||
fun enable(enabled: Boolean) {
|
fun enable(enabled: Boolean) {
|
||||||
this.enabled = enabled
|
this.enabled = enabled
|
||||||
SP.putBoolean(getSPName(), enabled)
|
@Suppress("DEPRECATION")
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(MainApp.instance()).edit().putBoolean(getSPName(), enabled).apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resetToDefault() {
|
fun resetToDefault() {
|
||||||
enable(defaultValue)
|
enable(defaultValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
enum class LTag(val tag: String) {
|
|
||||||
CORE("CORE"),
|
|
||||||
AUTOSENS("AUTOSENS"),
|
|
||||||
AUTOMATION("AUTOMATION"),
|
|
||||||
EVENTS("EVENTS"),
|
|
||||||
GLUCOSE("GLUCOSE"),
|
|
||||||
BGSOURCE("BGSOURCE"),
|
|
||||||
OVERVIEW("OVERVIEW"),
|
|
||||||
NOTIFICATION("NOTIFICATION"),
|
|
||||||
DATASERVICE("DATASERVICE"),
|
|
||||||
DATABASE("DATABASE"),
|
|
||||||
DATAFOOD("DATAFOOD"),
|
|
||||||
DATATREATMENTS("DATATREATMENTS"),
|
|
||||||
NSCLIENT("NSCLIENT"),
|
|
||||||
TIDEPOOL("TIDEPOOL"),
|
|
||||||
CONSTRAINTS("CONSTRAINTS"),
|
|
||||||
PUMP("PUMP"),
|
|
||||||
PUMPQUEUE("PUMPQUEUE"),
|
|
||||||
PUMPCOMM("PUMPCOMM"),
|
|
||||||
PUMPBTCOMM("PUMPBTCOMM"),
|
|
||||||
APS("APS"),
|
|
||||||
PROFILE("PROFILE"),
|
|
||||||
CONFIGBUILDER("CONFIGBUILDER"),
|
|
||||||
UI("UI"),
|
|
||||||
LOCATION("LOCATION"),
|
|
||||||
WEAR("WEAR"),
|
|
||||||
SMS("SMS"),
|
|
||||||
}
|
}
|
30
app/src/main/java/info/nightscout/androidaps/logging/LTag.kt
Normal file
30
app/src/main/java/info/nightscout/androidaps/logging/LTag.kt
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package info.nightscout.androidaps.logging
|
||||||
|
|
||||||
|
enum class LTag(val tag: String, val defaultValue : Boolean = true, val requiresRestart: Boolean = false) {
|
||||||
|
CORE("CORE"),
|
||||||
|
APS("APS"),
|
||||||
|
AUTOSENS("AUTOSENS", defaultValue = false),
|
||||||
|
AUTOMATION("AUTOMATION"),
|
||||||
|
BGSOURCE("BGSOURCE"),
|
||||||
|
CONFIGBUILDER("CONFIGBUILDER"),
|
||||||
|
CONSTRAINTS("CONSTRAINTS"),
|
||||||
|
DATABASE("DATABASE"),
|
||||||
|
DATAFOOD("DATAFOOD", defaultValue = false),
|
||||||
|
DATASERVICE("DATASERVICE"),
|
||||||
|
DATATREATMENTS("DATATREATMENTS"),
|
||||||
|
EVENTS("EVENTS", defaultValue = false, requiresRestart = true),
|
||||||
|
GLUCOSE("GLUCOSE"),
|
||||||
|
LOCATION("LOCATION"),
|
||||||
|
NOTIFICATION("NOTIFICATION"),
|
||||||
|
NSCLIENT("NSCLIENT"),
|
||||||
|
OVERVIEW("OVERVIEW", defaultValue = false),
|
||||||
|
PUMP("PUMP"),
|
||||||
|
PUMPBTCOMM("PUMPBTCOMM", defaultValue = false),
|
||||||
|
PUMPCOMM("PUMPCOMM"),
|
||||||
|
PUMPQUEUE("PUMPQUEUE"),
|
||||||
|
PROFILE("PROFILE"),
|
||||||
|
SMS("SMS"),
|
||||||
|
TIDEPOOL("TIDEPOOL"),
|
||||||
|
UI("UI", defaultValue = false),
|
||||||
|
WEAR("WEAR", defaultValue = false)
|
||||||
|
}
|
|
@ -366,7 +366,7 @@ import info.nightscout.androidaps.logging.StacktraceLoggerWrapper;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class DeviceStatus {
|
public class DeviceStatus {
|
||||||
private static Logger log = StacktraceLoggerWrapper.getLogger(L.APS);
|
private static Logger log = StacktraceLoggerWrapper.getLogger(L.NSCLIENT);
|
||||||
|
|
||||||
public String device = null;
|
public String device = null;
|
||||||
public JSONObject pump = null;
|
public JSONObject pump = null;
|
||||||
|
|
|
@ -334,8 +334,7 @@ public class LoopPlugin extends PluginBase {
|
||||||
Profile profile = profileFunction.getProfile();
|
Profile profile = profileFunction.getProfile();
|
||||||
|
|
||||||
if (profile == null || !profileFunction.isProfileValid("Loop")) {
|
if (profile == null || !profileFunction.isProfileValid("Loop")) {
|
||||||
if (L.isEnabled(L.APS))
|
getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected));
|
||||||
getAapsLogger().debug(LTag.APS, resourceHelper.gs(R.string.noprofileselected));
|
|
||||||
rxBus.send(new EventLoopSetLastRunGui(resourceHelper.gs(R.string.noprofileselected)));
|
rxBus.send(new EventLoopSetLastRunGui(resourceHelper.gs(R.string.noprofileselected)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,8 +109,7 @@ public class DetermineBasalAdapterMAJS {
|
||||||
|
|
||||||
// Parse the jsResult object to a JSON-String
|
// Parse the jsResult object to a JSON-String
|
||||||
String result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString();
|
String result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString();
|
||||||
if (L.isEnabled(L.APS))
|
aapsLogger.debug(LTag.APS, "Result: " + result);
|
||||||
aapsLogger.debug(LTag.APS, "Result: " + result);
|
|
||||||
try {
|
try {
|
||||||
determineBasalResultMA = new DetermineBasalResultMA(injector, jsResult, new JSONObject(result));
|
determineBasalResultMA = new DetermineBasalResultMA(injector, jsResult, new JSONObject(result));
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import info.nightscout.androidaps.activities.PreferencesActivity
|
||||||
import info.nightscout.androidaps.events.EventRebuildTabs
|
import info.nightscout.androidaps.events.EventRebuildTabs
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||||
|
|
|
@ -9,7 +9,6 @@ import java.util.ArrayList;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import dagger.Lazy;
|
|
||||||
import dagger.android.HasAndroidInjector;
|
import dagger.android.HasAndroidInjector;
|
||||||
import info.nightscout.androidaps.R;
|
import info.nightscout.androidaps.R;
|
||||||
import info.nightscout.androidaps.events.EventAppInitialized;
|
import info.nightscout.androidaps.events.EventAppInitialized;
|
||||||
|
@ -18,7 +17,6 @@ import info.nightscout.androidaps.events.EventRebuildTabs;
|
||||||
import info.nightscout.androidaps.interfaces.APSInterface;
|
import info.nightscout.androidaps.interfaces.APSInterface;
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
||||||
import info.nightscout.androidaps.interfaces.BgSourceInterface;
|
import info.nightscout.androidaps.interfaces.BgSourceInterface;
|
||||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider;
|
|
||||||
import info.nightscout.androidaps.interfaces.InsulinInterface;
|
import info.nightscout.androidaps.interfaces.InsulinInterface;
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||||
import info.nightscout.androidaps.interfaces.PluginDescription;
|
import info.nightscout.androidaps.interfaces.PluginDescription;
|
||||||
|
@ -30,13 +28,7 @@ import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
import info.nightscout.androidaps.logging.LTag;
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||||
import info.nightscout.androidaps.plugins.insulin.InsulinOrefRapidActingPlugin;
|
import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui;
|
||||||
import info.nightscout.androidaps.plugins.profile.local.LocalProfilePlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref0Plugin;
|
|
||||||
import info.nightscout.androidaps.plugins.sensitivity.SensitivityOref1Plugin;
|
|
||||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
|
||||||
import info.nightscout.androidaps.utils.OKDialog;
|
import info.nightscout.androidaps.utils.OKDialog;
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package info.nightscout.androidaps.plugins.configBuilder
|
package info.nightscout.androidaps.plugins.configBuilder
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.Config
|
||||||
import info.nightscout.androidaps.interfaces.*
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import java.util.*
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ class PluginStore @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var plugins = ArrayList<PluginBase>()
|
lateinit var plugins: List<@JvmSuppressWildcards PluginBase>
|
||||||
|
|
||||||
private var activeBgSource: BgSourceInterface? = null
|
private var activeBgSource: BgSourceInterface? = null
|
||||||
private var activePump: PumpInterface? = null
|
private var activePump: PumpInterface? = null
|
||||||
|
@ -41,11 +41,6 @@ class PluginStore @Inject constructor(
|
||||||
verifySelectionInCategories()
|
verifySelectionInCategories()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(pluginBase: PluginBase): ActivePluginProvider {
|
|
||||||
plugins.add(pluginBase)
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getDefaultPlugin(type: PluginType): PluginBase {
|
fun getDefaultPlugin(type: PluginType): PluginBase {
|
||||||
for (p in plugins)
|
for (p in plugins)
|
||||||
if (p.getType() == type && p.isDefault()) return p
|
if (p.getType() == type && p.isDefault()) return p
|
||||||
|
@ -88,14 +83,16 @@ class PluginStore @Inject constructor(
|
||||||
var pluginsInCategory: ArrayList<PluginBase>?
|
var pluginsInCategory: ArrayList<PluginBase>?
|
||||||
|
|
||||||
// PluginType.APS
|
// PluginType.APS
|
||||||
pluginsInCategory = getSpecificPluginsList(PluginType.APS)
|
if (!Config.NSCLIENT && !Config.PUMPCONTROL) {
|
||||||
activeAPS = getTheOneEnabledInArray(pluginsInCategory, PluginType.APS) as APSInterface?
|
pluginsInCategory = getSpecificPluginsList(PluginType.APS)
|
||||||
if (activeAPS == null) {
|
activeAPS = getTheOneEnabledInArray(pluginsInCategory, PluginType.APS) as APSInterface?
|
||||||
activeAPS = getDefaultPlugin(PluginType.APS) as APSInterface
|
if (activeAPS == null) {
|
||||||
(activeAPS as PluginBase).setPluginEnabled(PluginType.APS, true)
|
activeAPS = getDefaultPlugin(PluginType.APS) as APSInterface
|
||||||
aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting APSInterface")
|
(activeAPS as PluginBase).setPluginEnabled(PluginType.APS, true)
|
||||||
|
aapsLogger.debug(LTag.CONFIGBUILDER, "Defaulting APSInterface")
|
||||||
|
}
|
||||||
|
setFragmentVisiblities((activeAPS as PluginBase).name, pluginsInCategory, PluginType.APS)
|
||||||
}
|
}
|
||||||
setFragmentVisiblities((activeAPS as PluginBase).name, pluginsInCategory, PluginType.APS)
|
|
||||||
|
|
||||||
// PluginType.INSULIN
|
// PluginType.INSULIN
|
||||||
pluginsInCategory = getSpecificPluginsList(PluginType.INSULIN)
|
pluginsInCategory = getSpecificPluginsList(PluginType.INSULIN)
|
||||||
|
@ -190,6 +187,7 @@ class PluginStore @Inject constructor(
|
||||||
</T> */
|
</T> */
|
||||||
private fun <T> determineActivePlugin(pluginsInCategory: ArrayList<PluginBase>,
|
private fun <T> determineActivePlugin(pluginsInCategory: ArrayList<PluginBase>,
|
||||||
pluginType: PluginType): T? {
|
pluginType: PluginType): T? {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
val activePlugin = getTheOneEnabledInArray(pluginsInCategory, pluginType) as T?
|
val activePlugin = getTheOneEnabledInArray(pluginsInCategory, pluginType) as T?
|
||||||
if (activePlugin != null) {
|
if (activePlugin != null) {
|
||||||
setFragmentVisiblities((activePlugin as PluginBase).name, pluginsInCategory, pluginType)
|
setFragmentVisiblities((activePlugin as PluginBase).name, pluginsInCategory, pluginType)
|
||||||
|
@ -242,6 +240,6 @@ class PluginStore @Inject constructor(
|
||||||
override fun getActiveTreatments(): TreatmentsInterface =
|
override fun getActiveTreatments(): TreatmentsInterface =
|
||||||
activeTreatments ?: checkNotNull(activeTreatments) { "No treatments selected" }
|
activeTreatments ?: checkNotNull(activeTreatments) { "No treatments selected" }
|
||||||
|
|
||||||
override fun getPluginsList(): ArrayList<PluginBase> = plugins
|
override fun getPluginsList(): ArrayList<PluginBase> = ArrayList(plugins)
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package info.nightscout.androidaps.plugins.configBuilder
|
package info.nightscout.androidaps.plugins.configBuilder.events
|
||||||
|
|
||||||
import info.nightscout.androidaps.events.EventUpdateGui
|
import info.nightscout.androidaps.events.EventUpdateGui
|
||||||
|
|
|
@ -26,7 +26,7 @@ import info.nightscout.androidaps.plugins.constraints.objectives.dialogs.NtpProg
|
||||||
import info.nightscout.androidaps.plugins.constraints.objectives.events.EventNtpStatus
|
import info.nightscout.androidaps.plugins.constraints.objectives.events.EventNtpStatus
|
||||||
import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui
|
import info.nightscout.androidaps.plugins.constraints.objectives.events.EventObjectivesUpdateGui
|
||||||
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective.ExamTask
|
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Objective.ExamTask
|
||||||
import info.nightscout.androidaps.receivers.NetworkChangeReceiver
|
import info.nightscout.androidaps.receivers.ReceiverStatusStore
|
||||||
import info.nightscout.androidaps.setupwizard.events.EventSWUpdate
|
import info.nightscout.androidaps.setupwizard.events.EventSWUpdate
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
|
@ -48,6 +48,7 @@ class ObjectivesFragment : DaggerFragment() {
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||||
@Inject lateinit var objectivesPlugin: ObjectivesPlugin
|
@Inject lateinit var objectivesPlugin: ObjectivesPlugin
|
||||||
|
@Inject lateinit var receiverStatusStore: ReceiverStatusStore
|
||||||
|
|
||||||
private val objectivesAdapter = ObjectivesAdapter()
|
private val objectivesAdapter = ObjectivesAdapter()
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
@ -223,7 +224,7 @@ class ObjectivesFragment : DaggerFragment() {
|
||||||
holder.accomplished.text = resourceHelper.gs(R.string.accomplished, DateUtil.dateAndTimeString(objective.accomplishedOn))
|
holder.accomplished.text = resourceHelper.gs(R.string.accomplished, DateUtil.dateAndTimeString(objective.accomplishedOn))
|
||||||
holder.accomplished.setTextColor(-0x3e3e3f)
|
holder.accomplished.setTextColor(-0x3e3e3f)
|
||||||
holder.verify.setOnClickListener {
|
holder.verify.setOnClickListener {
|
||||||
NetworkChangeReceiver.grabNetworkStatus(context)
|
receiverStatusStore.updateNetworkStatus()
|
||||||
if (objectives_fake.isChecked) {
|
if (objectives_fake.isChecked) {
|
||||||
objective.accomplishedOn = DateUtil.now()
|
objective.accomplishedOn = DateUtil.now()
|
||||||
scrollToCurrentObjective()
|
scrollToCurrentObjective()
|
||||||
|
@ -257,12 +258,12 @@ class ObjectivesFragment : DaggerFragment() {
|
||||||
rxBus.send(EventNtpStatus(resourceHelper.gs(R.string.failedretrievetime), 99))
|
rxBus.send(EventNtpStatus(resourceHelper.gs(R.string.failedretrievetime), 99))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, NetworkChangeReceiver.isConnected())
|
}, receiverStatusStore.isConnected)
|
||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
holder.start.setOnClickListener {
|
holder.start.setOnClickListener {
|
||||||
NetworkChangeReceiver.grabNetworkStatus(context)
|
receiverStatusStore.updateNetworkStatus()
|
||||||
if (objectives_fake.isChecked) {
|
if (objectives_fake.isChecked) {
|
||||||
objective.startedOn = DateUtil.now()
|
objective.startedOn = DateUtil.now()
|
||||||
scrollToCurrentObjective()
|
scrollToCurrentObjective()
|
||||||
|
@ -292,7 +293,7 @@ class ObjectivesFragment : DaggerFragment() {
|
||||||
rxBus.send(EventNtpStatus(resourceHelper.gs(R.string.failedretrievetime), 99))
|
rxBus.send(EventNtpStatus(resourceHelper.gs(R.string.failedretrievetime), 99))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, NetworkChangeReceiver.isConnected())
|
}, receiverStatusStore.isConnected)
|
||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
holder.unStart.setOnClickListener {
|
holder.unStart.setOnClickListener {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import android.os.Build
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.events.EventBTChange
|
||||||
import info.nightscout.androidaps.events.EventChargingState
|
import info.nightscout.androidaps.events.EventChargingState
|
||||||
import info.nightscout.androidaps.events.EventLocationChange
|
import info.nightscout.androidaps.events.EventLocationChange
|
||||||
import info.nightscout.androidaps.events.EventNetworkChange
|
import info.nightscout.androidaps.events.EventNetworkChange
|
||||||
|
@ -38,6 +39,7 @@ import org.json.JSONObject
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class AutomationPlugin @Inject constructor(
|
class AutomationPlugin @Inject constructor(
|
||||||
|
@ -65,6 +67,7 @@ class AutomationPlugin @Inject constructor(
|
||||||
|
|
||||||
val automationEvents = ArrayList<AutomationEvent>()
|
val automationEvents = ArrayList<AutomationEvent>()
|
||||||
var executionLog: MutableList<String> = ArrayList()
|
var executionLog: MutableList<String> = ArrayList()
|
||||||
|
var btConnects : MutableList<EventBTChange> = ArrayList()
|
||||||
|
|
||||||
private val loopHandler = Handler()
|
private val loopHandler = Handler()
|
||||||
private lateinit var refreshLoop: Runnable
|
private lateinit var refreshLoop: Runnable
|
||||||
|
@ -123,6 +126,14 @@ class AutomationPlugin @Inject constructor(
|
||||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||||
.observeOn(Schedulers.io())
|
.observeOn(Schedulers.io())
|
||||||
.subscribe({ processActions() }, { fabricPrivacy.logException(it) })
|
.subscribe({ processActions() }, { fabricPrivacy.logException(it) })
|
||||||
|
disposable += rxBus
|
||||||
|
.toObservable(EventBTChange::class.java)
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe({
|
||||||
|
aapsLogger.debug(LTag.AUTOMATION, "Grabbed new BT event: $it")
|
||||||
|
btConnects.add(it)
|
||||||
|
processActions()
|
||||||
|
}, { fabricPrivacy.logException(it) })
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
|
@ -197,6 +208,12 @@ class AutomationPlugin @Inject constructor(
|
||||||
event.lastRun = DateUtil.now()
|
event.lastRun = DateUtil.now()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// we cannot detect connected BT devices
|
||||||
|
// so let's collect all connection/disconnections between 2 runs of processActions()
|
||||||
|
// TriggerBTDevice can pick up and process these events
|
||||||
|
// after processing clear events to prevent repeated actions
|
||||||
|
btConnects.clear()
|
||||||
|
|
||||||
storeToSP() // save last run time
|
storeToSP() // save last run time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,8 +248,8 @@ class AutomationPlugin @Inject constructor(
|
||||||
TriggerLocation(injector),
|
TriggerLocation(injector),
|
||||||
TriggerAutosensValue(injector),
|
TriggerAutosensValue(injector),
|
||||||
TriggerBolusAgo(injector),
|
TriggerBolusAgo(injector),
|
||||||
TriggerPumpLastConnection(injector)
|
TriggerPumpLastConnection(injector),
|
||||||
|
TriggerBTDevice(injector)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuil
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationUserMessage
|
||||||
import info.nightscout.androidaps.queue.Callback
|
import info.nightscout.androidaps.queue.Callback
|
||||||
import info.nightscout.androidaps.utils.JsonHelper
|
import info.nightscout.androidaps.utils.JsonHelper
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
@ -30,7 +31,7 @@ class ActionNotification(injector: HasAndroidInjector) : Action(injector) {
|
||||||
@DrawableRes override fun icon(): Int = R.drawable.ic_notifications
|
@DrawableRes override fun icon(): Int = R.drawable.ic_notifications
|
||||||
|
|
||||||
override fun doAction(callback: Callback) {
|
override fun doAction(callback: Callback) {
|
||||||
val notification = Notification(Notification.USERMESSAGE, text.value, Notification.URGENT)
|
val notification = NotificationUserMessage(text.value)
|
||||||
rxBus.send(EventNewNotification(notification))
|
rxBus.send(EventNewNotification(notification))
|
||||||
NSUpload.uploadError(text.value)
|
NSUpload.uploadError(text.value)
|
||||||
rxBus.send(EventRefreshOverview("ActionNotification"))
|
rxBus.send(EventRefreshOverview("ActionNotification"))
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
package info.nightscout.androidaps.plugins.general.automation.elements
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.AdapterView
|
||||||
|
import android.widget.ArrayAdapter
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.Spinner
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class ComparatorConnect(injector: HasAndroidInjector) : Element(injector) {
|
||||||
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
|
|
||||||
|
enum class Compare {
|
||||||
|
ON_CONNECT, ON_DISCONNECT;
|
||||||
|
|
||||||
|
@get:StringRes val stringRes: Int
|
||||||
|
get() = when (this) {
|
||||||
|
ON_CONNECT -> R.string.onconnect
|
||||||
|
ON_DISCONNECT -> R.string.ondisconnect
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun labels(resourceHelper: ResourceHelper): List<String> {
|
||||||
|
val list: MutableList<String> = ArrayList()
|
||||||
|
for (c in values()) list.add(resourceHelper.gs(c.stringRes))
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(injector: HasAndroidInjector, value: Compare) : this(injector) {
|
||||||
|
this.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
var value = Compare.ON_CONNECT
|
||||||
|
|
||||||
|
override fun addToLayout(root: LinearLayout) {
|
||||||
|
val spinner = Spinner(root.context)
|
||||||
|
val spinnerArrayAdapter = ArrayAdapter(root.context, R.layout.spinner_centered, Compare.labels(resourceHelper))
|
||||||
|
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||||
|
spinner.adapter = spinnerArrayAdapter
|
||||||
|
val spinnerParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||||
|
spinnerParams.setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4))
|
||||||
|
spinner.layoutParams = spinnerParams
|
||||||
|
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||||
|
override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
|
||||||
|
value = Compare.values()[position]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNothingSelected(parent: AdapterView<*>?) {}
|
||||||
|
}
|
||||||
|
spinner.setSelection(value.ordinal)
|
||||||
|
root.addView(spinner)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package info.nightscout.androidaps.plugins.general.automation.elements
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.AdapterView
|
||||||
|
import android.widget.ArrayAdapter
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.Spinner
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class InputDropdownMenu(injector: HasAndroidInjector) : Element(injector) {
|
||||||
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
|
|
||||||
|
private var itemList: ArrayList<CharSequence> = ArrayList()
|
||||||
|
var value: String = ""
|
||||||
|
|
||||||
|
constructor(injector: HasAndroidInjector, name: String) : this(injector) {
|
||||||
|
value = name
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(injector: HasAndroidInjector, another: InputDropdownMenu) : this(injector) {
|
||||||
|
value = another.value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addToLayout(root: LinearLayout) {
|
||||||
|
val spinner = Spinner(root.context)
|
||||||
|
spinner.adapter = ArrayAdapter(root.context,
|
||||||
|
R.layout.spinner_centered, itemList).also {
|
||||||
|
it.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||||
|
}
|
||||||
|
spinner.layoutParams = LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
).also { it.setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4)) }
|
||||||
|
|
||||||
|
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||||
|
override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
|
||||||
|
setValue(itemList[position].toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNothingSelected(parent: AdapterView<*>?) {}
|
||||||
|
}
|
||||||
|
spinner.setSelection(0)
|
||||||
|
root.addView(LinearLayout(root.context).also {
|
||||||
|
it.orientation = LinearLayout.VERTICAL
|
||||||
|
it.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||||
|
it.addView(spinner)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setValue(name: String): InputDropdownMenu {
|
||||||
|
value = name
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setList(values: ArrayList<CharSequence>) {
|
||||||
|
itemList = ArrayList(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
// For testing only
|
||||||
|
fun add(item: String) {
|
||||||
|
itemList.add(item)
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,7 +57,7 @@ class InputTime(injector: HasAndroidInjector) : Element(injector) {
|
||||||
root.addView(l)
|
root.addView(l)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toMills(minutesSinceMidnight: Int): Long = MidnightTime.calc() + T.mins(minutesSinceMidnight.toLong()).msecs()
|
private fun toMills(minutesSinceMidnight: Int): Long = MidnightTime.calcPlusMinutes(minutesSinceMidnight)
|
||||||
|
|
||||||
private fun getMinSinceMidnight(time: Long): Int = Profile.secondsFromMidnight(time) / 60
|
private fun getMinSinceMidnight(time: Long): Int = Profile.secondsFromMidnight(time) / 60
|
||||||
}
|
}
|
|
@ -80,7 +80,7 @@ class InputTimeRange(injector: HasAndroidInjector) : Element(injector) {
|
||||||
root.addView(l)
|
root.addView(l)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toMills(minutesSinceMidnight: Int): Long = MidnightTime.calc() + T.mins(minutesSinceMidnight.toLong()).msecs()
|
private fun toMills(minutesSinceMidnight: Int): Long = MidnightTime.calcPlusMinutes(minutesSinceMidnight)
|
||||||
|
|
||||||
private fun getMinSinceMidnight(time: Long): Int = Profile.secondsFromMidnight(time) / 60
|
private fun getMinSinceMidnight(time: Long): Int = Profile.secondsFromMidnight(time) / 60
|
||||||
}
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
package info.nightscout.androidaps.plugins.general.automation.triggers
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothAdapter
|
||||||
|
import android.content.Context
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import com.google.common.base.Optional
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.events.EventBTChange
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.general.automation.elements.ComparatorConnect
|
||||||
|
import info.nightscout.androidaps.plugins.general.automation.elements.InputDropdownMenu
|
||||||
|
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
|
||||||
|
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel
|
||||||
|
import info.nightscout.androidaps.utils.JsonHelper
|
||||||
|
import org.json.JSONObject
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class TriggerBTDevice(injector: HasAndroidInjector) : Trigger(injector) {
|
||||||
|
@Inject lateinit var context: Context
|
||||||
|
@Inject lateinit var automationPlugin: AutomationPlugin
|
||||||
|
|
||||||
|
var btDevice = InputDropdownMenu(injector, "")
|
||||||
|
var comparator: ComparatorConnect = ComparatorConnect(injector)
|
||||||
|
|
||||||
|
private constructor(injector: HasAndroidInjector, triggerBTDevice: TriggerBTDevice) : this(injector) {
|
||||||
|
comparator = ComparatorConnect(injector, triggerBTDevice.comparator.value)
|
||||||
|
btDevice.value = triggerBTDevice.btDevice.value
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
override fun shouldRun(): Boolean {
|
||||||
|
if (eventExists()) {
|
||||||
|
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized override fun toJSON(): String {
|
||||||
|
val data = JSONObject()
|
||||||
|
.put("comparator", comparator.value.toString())
|
||||||
|
.put("name", btDevice.value)
|
||||||
|
return JSONObject()
|
||||||
|
.put("type", this::class.java.name)
|
||||||
|
.put("data", data)
|
||||||
|
.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fromJSON(data: String): Trigger {
|
||||||
|
val d = JSONObject(data)
|
||||||
|
btDevice.value = JsonHelper.safeGetString(d, "name")!!
|
||||||
|
comparator.value = ComparatorConnect.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")!!)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun friendlyName(): Int = R.string.btdevice
|
||||||
|
|
||||||
|
override fun friendlyDescription(): String =
|
||||||
|
resourceHelper.gs(R.string.btdevicecompared, btDevice.value, resourceHelper.gs(comparator.value.stringRes))
|
||||||
|
|
||||||
|
override fun icon(): Optional<Int?> = Optional.of(R.drawable.ic_bluetooth_white_48dp)
|
||||||
|
|
||||||
|
override fun duplicate(): Trigger = TriggerBTDevice(injector, this)
|
||||||
|
|
||||||
|
override fun generateDialog(root: LinearLayout) {
|
||||||
|
val pairedDevices = devicesPaired()
|
||||||
|
btDevice.setList(pairedDevices)
|
||||||
|
LayoutBuilder()
|
||||||
|
.add(StaticLabel(injector, R.string.btdevice, this))
|
||||||
|
.add(btDevice)
|
||||||
|
.add(comparator)
|
||||||
|
.build(root)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the list of paired BT devices to use in dropdown menu
|
||||||
|
private fun devicesPaired(): ArrayList<CharSequence> {
|
||||||
|
val s = ArrayList<CharSequence>()
|
||||||
|
BluetoothAdapter.getDefaultAdapter()?.bondedDevices?.forEach { s.add(it.name) }
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun eventExists(): Boolean {
|
||||||
|
automationPlugin.btConnects.forEach {
|
||||||
|
if (btDevice.value == it.deviceName) {
|
||||||
|
if (comparator.value == ComparatorConnect.Compare.ON_CONNECT && it.state == EventBTChange.Change.CONNECT) return true
|
||||||
|
if (comparator.value == ComparatorConnect.Compare.ON_DISCONNECT && it.state == EventBTChange.Change.DISCONNECT) return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
|
@ -93,7 +93,7 @@ class TriggerRecurringTime(injector: HasAndroidInjector) : Trigger(injector) {
|
||||||
|
|
||||||
override fun duplicate(): Trigger = TriggerRecurringTime(injector, this)
|
override fun duplicate(): Trigger = TriggerRecurringTime(injector, this)
|
||||||
|
|
||||||
private fun toMills(minutesSinceMidnight: Int): Long = MidnightTime.calc() + T.mins(minutesSinceMidnight.toLong()).msecs()
|
private fun toMills(minutesSinceMidnight: Int): Long = MidnightTime.calcPlusMinutes(minutesSinceMidnight)
|
||||||
|
|
||||||
private fun getMinSinceMidnight(time: Long): Int = Profile.secondsFromMidnight(time) / 60
|
private fun getMinSinceMidnight(time: Long): Int = Profile.secondsFromMidnight(time) / 60
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ class TriggerTimeRange(injector: HasAndroidInjector) : Trigger(injector) {
|
||||||
|
|
||||||
override fun duplicate(): Trigger = TriggerTimeRange(injector, range.start, range.end)
|
override fun duplicate(): Trigger = TriggerTimeRange(injector, range.start, range.end)
|
||||||
|
|
||||||
private fun toMills(minutesSinceMidnight: Int): Long = MidnightTime.calc() + T.mins(minutesSinceMidnight.toLong()).msecs()
|
private fun toMills(minutesSinceMidnight: Int): Long = MidnightTime.calcPlusMinutes(minutesSinceMidnight)
|
||||||
|
|
||||||
private fun getMinSinceMidnight(time: Long): Int = Profile.secondsFromMidnight(time) / 60
|
private fun getMinSinceMidnight(time: Long): Int = Profile.secondsFromMidnight(time) / 60
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,14 @@ import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithE
|
||||||
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
|
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
|
||||||
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel
|
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel
|
||||||
import info.nightscout.androidaps.receivers.NetworkChangeReceiver
|
import info.nightscout.androidaps.receivers.NetworkChangeReceiver
|
||||||
|
import info.nightscout.androidaps.receivers.ReceiverStatusStore
|
||||||
import info.nightscout.androidaps.utils.JsonHelper
|
import info.nightscout.androidaps.utils.JsonHelper
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
class TriggerWifiSsid(injector: HasAndroidInjector) : Trigger(injector) {
|
class TriggerWifiSsid(injector: HasAndroidInjector) : Trigger(injector) {
|
||||||
|
@Inject lateinit var receiverStatusStore: ReceiverStatusStore
|
||||||
|
|
||||||
var ssid = InputString(injector)
|
var ssid = InputString(injector)
|
||||||
var comparator = Comparator(injector)
|
var comparator = Comparator(injector)
|
||||||
|
|
||||||
|
@ -39,7 +43,7 @@ class TriggerWifiSsid(injector: HasAndroidInjector) : Trigger(injector) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun shouldRun(): Boolean {
|
override fun shouldRun(): Boolean {
|
||||||
val eventNetworkChange = NetworkChangeReceiver.getLastEvent() ?: return false
|
val eventNetworkChange = receiverStatusStore.lastNetworkEvent ?: return false
|
||||||
if (!eventNetworkChange.wifiConnected && comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) {
|
if (!eventNetworkChange.wifiConnected && comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) {
|
||||||
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
|
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -1,129 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.general.maintenance;
|
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.os.Environment;
|
|
||||||
import androidx.preference.PreferenceManager;
|
|
||||||
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.MainApp;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.events.EventAppExit;
|
|
||||||
import info.nightscout.androidaps.logging.L;
|
|
||||||
import info.nightscout.androidaps.logging.StacktraceLoggerWrapper;
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
|
||||||
import info.nightscout.androidaps.utils.OKDialog;
|
|
||||||
import info.nightscout.androidaps.utils.SP;
|
|
||||||
import info.nightscout.androidaps.utils.ToastUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by mike on 03.07.2016.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class ImportExportPrefs {
|
|
||||||
private static Logger log = StacktraceLoggerWrapper.getLogger(L.CORE);
|
|
||||||
private static File path = new File(Environment.getExternalStorageDirectory().toString());
|
|
||||||
static public final File file = new File(path, MainApp.gs(R.string.app_name) + "Preferences");
|
|
||||||
|
|
||||||
private static final int REQUEST_EXTERNAL_STORAGE = 1;
|
|
||||||
private static String[] PERMISSIONS_STORAGE = {
|
|
||||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
|
||||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
|
||||||
};
|
|
||||||
|
|
||||||
static void verifyStoragePermissions(Fragment fragment) {
|
|
||||||
int permission = ContextCompat.checkSelfPermission(fragment.getContext(),
|
|
||||||
Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
|
||||||
|
|
||||||
if (permission != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
// We don't have permission so prompt the user
|
|
||||||
fragment.requestPermissions(PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void exportSharedPreferences(final Fragment f) {
|
|
||||||
exportSharedPreferences(f.getContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void exportSharedPreferences(final Context context) {
|
|
||||||
OKDialog.showConfirmation(context, MainApp.gs(R.string.maintenance), MainApp.gs(R.string.export_to) + " " + file + " ?", () -> {
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
|
||||||
try {
|
|
||||||
FileWriter fw = new FileWriter(file);
|
|
||||||
PrintWriter pw = new PrintWriter(fw);
|
|
||||||
Map<String, ?> prefsMap = prefs.getAll();
|
|
||||||
for (Map.Entry<String, ?> entry : prefsMap.entrySet()) {
|
|
||||||
pw.println(entry.getKey() + "::" + entry.getValue().toString());
|
|
||||||
}
|
|
||||||
pw.close();
|
|
||||||
fw.close();
|
|
||||||
ToastUtils.showToastInUiThread(context, MainApp.gs(R.string.exported));
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
ToastUtils.showToastInUiThread(context, MainApp.gs(R.string.filenotfound) + " " + file);
|
|
||||||
log.error("Unhandled exception", e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static void importSharedPreferences(final Fragment fragment) {
|
|
||||||
importSharedPreferences(fragment.getContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void importSharedPreferences(final Context context) {
|
|
||||||
OKDialog.showConfirmation(context, MainApp.gs(R.string.maintenance), MainApp.gs(R.string.import_from) + " " + file + " ?", () -> {
|
|
||||||
String line;
|
|
||||||
String[] lineParts;
|
|
||||||
try {
|
|
||||||
SP.clear();
|
|
||||||
|
|
||||||
BufferedReader reader = new BufferedReader(new FileReader(file));
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
lineParts = line.split("::");
|
|
||||||
if (lineParts.length == 2) {
|
|
||||||
if (lineParts[1].equals("true") || lineParts[1].equals("false")) {
|
|
||||||
SP.putBoolean(lineParts[0], Boolean.parseBoolean(lineParts[1]));
|
|
||||||
} else {
|
|
||||||
SP.putString(lineParts[0], lineParts[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reader.close();
|
|
||||||
SP.putBoolean(R.string.key_setupwizard_processed, true);
|
|
||||||
OKDialog.show(context, MainApp.gs(R.string.setting_imported), MainApp.gs(R.string.restartingapp), () -> {
|
|
||||||
log.debug("Exiting");
|
|
||||||
RxBus.Companion.getINSTANCE().send(new EventAppExit());
|
|
||||||
if (context instanceof Activity) {
|
|
||||||
((Activity) context).finish();
|
|
||||||
}
|
|
||||||
System.runFinalization();
|
|
||||||
System.exit(0);
|
|
||||||
});
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
ToastUtils.showToastInUiThread(context, MainApp.gs(R.string.filenotfound) + " " + file);
|
|
||||||
log.error("Unhandled exception", e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Unhandled exception", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,340 @@
|
||||||
|
package info.nightscout.androidaps.plugins.general.maintenance
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.app.Activity
|
||||||
|
import android.bluetooth.BluetoothAdapter
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Environment
|
||||||
|
import android.provider.Settings
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import info.nightscout.androidaps.BuildConfig
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.activities.PreferencesActivity
|
||||||
|
import info.nightscout.androidaps.events.EventAppExit
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import info.nightscout.androidaps.plugins.general.maintenance.formats.*
|
||||||
|
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePassword
|
||||||
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
|
import info.nightscout.androidaps.utils.OKDialog
|
||||||
|
import info.nightscout.androidaps.utils.OKDialog.show
|
||||||
|
import info.nightscout.androidaps.utils.ToastUtils
|
||||||
|
import info.nightscout.androidaps.utils.alertDialogs.PrefImportSummaryDialog
|
||||||
|
import info.nightscout.androidaps.utils.alertDialogs.TwoMessagesAlertDialog
|
||||||
|
import info.nightscout.androidaps.utils.alertDialogs.WarningDialog
|
||||||
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
|
import info.nightscout.androidaps.utils.protection.PasswordCheck
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import org.joda.time.DateTime
|
||||||
|
import org.joda.time.Days
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileNotFoundException
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by mike on 03.07.2016.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private const val REQUEST_EXTERNAL_STORAGE = 1
|
||||||
|
private val PERMISSIONS_STORAGE = arrayOf(
|
||||||
|
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||||
|
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||||
|
)
|
||||||
|
|
||||||
|
private const val IMPORT_AGE_NOT_YET_OLD_DAYS = 60
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class ImportExportPrefs @Inject constructor(
|
||||||
|
private var log: AAPSLogger,
|
||||||
|
private val resourceHelper: ResourceHelper,
|
||||||
|
private val sp: SP,
|
||||||
|
private val buildHelper: BuildHelper,
|
||||||
|
private val otp: OneTimePassword,
|
||||||
|
private val rxBus: RxBusWrapper,
|
||||||
|
private val passwordCheck: PasswordCheck,
|
||||||
|
private val classicPrefsFormat: ClassicPrefsFormat,
|
||||||
|
private val encryptedPrefsFormat: EncryptedPrefsFormat
|
||||||
|
) {
|
||||||
|
|
||||||
|
val TAG = LTag.CORE
|
||||||
|
|
||||||
|
private val path = File(Environment.getExternalStorageDirectory().toString())
|
||||||
|
|
||||||
|
private val file = File(path, resourceHelper.gs(R.string.app_name) + "Preferences")
|
||||||
|
private val encFile = File(path, resourceHelper.gs(R.string.app_name) + "Preferences.json")
|
||||||
|
|
||||||
|
fun prefsImportFile(): File {
|
||||||
|
return if (encFile.exists()) encFile else file
|
||||||
|
}
|
||||||
|
|
||||||
|
fun prefsFileExists(): Boolean {
|
||||||
|
return encFile.exists() || file.exists()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun exportSharedPreferences(f: Fragment) {
|
||||||
|
f.activity?.let { exportSharedPreferences(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun verifyStoragePermissions(fragment: Fragment) {
|
||||||
|
fragment.context?.let {
|
||||||
|
val permission = ContextCompat.checkSelfPermission(it,
|
||||||
|
Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||||
|
if (permission != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
// We don't have permission so prompt the user
|
||||||
|
fragment.requestPermissions(PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun prepareMetadata(context: Context): Map<PrefsMetadataKey, PrefMetadata> {
|
||||||
|
|
||||||
|
val metadata: MutableMap<PrefsMetadataKey, PrefMetadata> = mutableMapOf()
|
||||||
|
|
||||||
|
metadata[PrefsMetadataKey.DEVICE_NAME] = PrefMetadata(detectUserName(context), PrefsStatus.OK)
|
||||||
|
metadata[PrefsMetadataKey.CREATED_AT] = PrefMetadata(DateUtil.toISOString(Date()), PrefsStatus.OK)
|
||||||
|
metadata[PrefsMetadataKey.AAPS_VERSION] = PrefMetadata(BuildConfig.VERSION_NAME, PrefsStatus.OK)
|
||||||
|
metadata[PrefsMetadataKey.AAPS_FLAVOUR] = PrefMetadata(BuildConfig.FLAVOR, PrefsStatus.OK)
|
||||||
|
metadata[PrefsMetadataKey.DEVICE_MODEL] = PrefMetadata(getCurrentDeviceModelString(), PrefsStatus.OK)
|
||||||
|
|
||||||
|
if (prefsEncryptionIsDisabled()) {
|
||||||
|
metadata[PrefsMetadataKey.ENCRYPTION] = PrefMetadata("Disabled", PrefsStatus.DISABLED)
|
||||||
|
} else {
|
||||||
|
metadata[PrefsMetadataKey.ENCRYPTION] = PrefMetadata("Enabled", PrefsStatus.OK)
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadata
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun detectUserName(context: Context): String {
|
||||||
|
// based on https://medium.com/@pribble88/how-to-get-an-android-device-nickname-4b4700b3068c
|
||||||
|
val n1 = Settings.System.getString(context.contentResolver, "bluetooth_name")
|
||||||
|
val n2 = Settings.Secure.getString(context.contentResolver, "bluetooth_name")
|
||||||
|
val n3 = BluetoothAdapter.getDefaultAdapter()?.name
|
||||||
|
val n4 = Settings.System.getString(context.contentResolver, "device_name")
|
||||||
|
val n5 = Settings.Secure.getString(context.contentResolver, "lock_screen_owner_info")
|
||||||
|
val n6 = Settings.Global.getString(context.contentResolver, "device_name")
|
||||||
|
|
||||||
|
// name we use for SMS OTP token in communicator
|
||||||
|
val otpName = otp.name().trim()
|
||||||
|
val defaultOtpName = resourceHelper.gs(R.string.smscommunicator_default_user_display_name)
|
||||||
|
|
||||||
|
// name we detect from OS
|
||||||
|
val systemName = n1 ?: n2 ?: n3 ?: n4 ?: n5 ?: n6 ?: defaultOtpName
|
||||||
|
val name = if (otpName.length > 0 && otpName != defaultOtpName) otpName else systemName
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCurrentDeviceModelString() =
|
||||||
|
Build.MANUFACTURER + " " + Build.MODEL + " (" + Build.DEVICE + ")"
|
||||||
|
|
||||||
|
private fun prefsEncryptionIsDisabled() =
|
||||||
|
buildHelper.isEngineeringMode() && !sp.getBoolean(resourceHelper.gs(R.string.key_maintenance_encrypt_exported_prefs), true)
|
||||||
|
|
||||||
|
private fun askForMasterPass(activity: Activity, @StringRes canceledMsg: Int, then: ((password: String) -> Unit)) {
|
||||||
|
passwordCheck.queryPassword(activity, R.string.master_password, R.string.key_master_password, { password ->
|
||||||
|
then(password)
|
||||||
|
}, {
|
||||||
|
ToastUtils.warnToast(activity, resourceHelper.gs(canceledMsg))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun askForMasterPassIfNeeded(activity: Activity, @StringRes canceledMsg: Int, then: ((password: String) -> Unit)) {
|
||||||
|
if (prefsEncryptionIsDisabled()) {
|
||||||
|
then("")
|
||||||
|
} else {
|
||||||
|
askForMasterPass(activity, canceledMsg, then)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assureMasterPasswordSet(activity: Activity, @StringRes wrongPwdTitle: Int): Boolean {
|
||||||
|
if (!sp.contains(R.string.key_master_password) || (sp.getString(R.string.key_master_password, "") == "")) {
|
||||||
|
WarningDialog.showWarning(activity,
|
||||||
|
resourceHelper.gs(wrongPwdTitle),
|
||||||
|
resourceHelper.gs(R.string.master_password_missing, resourceHelper.gs(R.string.configbuilder_general), resourceHelper.gs(R.string.protection)),
|
||||||
|
R.string.nav_preferences, {
|
||||||
|
val intent = Intent(activity, PreferencesActivity::class.java).apply {
|
||||||
|
putExtra("id", R.xml.pref_general)
|
||||||
|
}
|
||||||
|
activity.startActivity(intent)
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun askToConfirmExport(activity: Activity, then: ((password: String) -> Unit)) {
|
||||||
|
if (!prefsEncryptionIsDisabled() && !assureMasterPasswordSet(activity, R.string.nav_export)) return
|
||||||
|
|
||||||
|
TwoMessagesAlertDialog.showAlert(activity, resourceHelper.gs(R.string.nav_export),
|
||||||
|
resourceHelper.gs(R.string.export_to) + " " + encFile + " ?",
|
||||||
|
resourceHelper.gs(R.string.password_preferences_encrypt_prompt), {
|
||||||
|
askForMasterPassIfNeeded(activity, R.string.preferences_export_canceled, then)
|
||||||
|
}, null, R.drawable.ic_header_export)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun askToConfirmImport(activity: Activity, fileToImport: File, then: ((password: String) -> Unit)) {
|
||||||
|
|
||||||
|
if (encFile.exists()) {
|
||||||
|
if (!assureMasterPasswordSet(activity, R.string.nav_import)) return
|
||||||
|
|
||||||
|
TwoMessagesAlertDialog.showAlert(activity, resourceHelper.gs(R.string.nav_import),
|
||||||
|
resourceHelper.gs(R.string.import_from) + " " + fileToImport + " ?",
|
||||||
|
resourceHelper.gs(R.string.password_preferences_decrypt_prompt), {
|
||||||
|
askForMasterPass(activity, R.string.preferences_import_canceled, then)
|
||||||
|
}, null, R.drawable.ic_header_import)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.nav_import),
|
||||||
|
resourceHelper.gs(R.string.import_from) + " " + fileToImport + " ?",
|
||||||
|
Runnable { then("") })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun exportSharedPreferences(activity: Activity) {
|
||||||
|
askToConfirmExport(activity) { password ->
|
||||||
|
try {
|
||||||
|
val entries: MutableMap<String, String> = mutableMapOf()
|
||||||
|
for ((key, value) in sp.getAll()) {
|
||||||
|
entries[key] = value.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
val prefs = Prefs(entries, prepareMetadata(activity))
|
||||||
|
|
||||||
|
classicPrefsFormat.savePreferences(file, prefs)
|
||||||
|
encryptedPrefsFormat.savePreferences(encFile, prefs, password)
|
||||||
|
|
||||||
|
ToastUtils.okToast(activity, resourceHelper.gs(R.string.exported))
|
||||||
|
} catch (e: FileNotFoundException) {
|
||||||
|
ToastUtils.errorToast(activity, resourceHelper.gs(R.string.filenotfound) + " " + encFile)
|
||||||
|
log.error(TAG, "Unhandled exception", e)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
ToastUtils.errorToast(activity, e.message)
|
||||||
|
log.error(TAG, "Unhandled exception", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun importSharedPreferences(fragment: Fragment) {
|
||||||
|
fragment.activity?.let { importSharedPreferences(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun importSharedPreferences(activity: Activity) {
|
||||||
|
|
||||||
|
val importFile = prefsImportFile()
|
||||||
|
|
||||||
|
askToConfirmImport(activity, importFile) { password ->
|
||||||
|
|
||||||
|
val format: PrefsFormat = if (encFile.exists()) encryptedPrefsFormat else classicPrefsFormat
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
val prefs = format.loadPreferences(importFile, password)
|
||||||
|
prefs.metadata = checkMetadata(prefs.metadata)
|
||||||
|
|
||||||
|
// import is OK when we do not have errors (warnings are allowed)
|
||||||
|
val importOk = checkIfImportIsOk(prefs)
|
||||||
|
|
||||||
|
// if at end we allow to import preferences
|
||||||
|
val importPossible = (importOk || buildHelper.isEngineeringMode()) && (prefs.values.size > 0)
|
||||||
|
|
||||||
|
PrefImportSummaryDialog.showSummary(activity, importOk, importPossible, prefs, {
|
||||||
|
if (importPossible) {
|
||||||
|
sp.clear()
|
||||||
|
for ((key, value) in prefs.values) {
|
||||||
|
if (value == "true" || value == "false") {
|
||||||
|
sp.putBoolean(key, value.toBoolean())
|
||||||
|
} else {
|
||||||
|
sp.putString(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
restartAppAfterImport(activity)
|
||||||
|
} else {
|
||||||
|
// for impossible imports it should not be called
|
||||||
|
ToastUtils.errorToast(activity, "Cannot import preferences!")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (e: PrefFileNotFoundError) {
|
||||||
|
ToastUtils.errorToast(activity, resourceHelper.gs(R.string.filenotfound) + " " + importFile)
|
||||||
|
log.error(TAG, "Unhandled exception", e)
|
||||||
|
} catch (e: PrefIOError) {
|
||||||
|
log.error(TAG, "Unhandled exception", e)
|
||||||
|
ToastUtils.errorToast(activity, e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check metadata for known issues, change their status and add info with explanations
|
||||||
|
private fun checkMetadata(metadata: Map<PrefsMetadataKey, PrefMetadata>): Map<PrefsMetadataKey, PrefMetadata> {
|
||||||
|
val meta = metadata.toMutableMap()
|
||||||
|
|
||||||
|
meta[PrefsMetadataKey.AAPS_FLAVOUR]?.let { flavour ->
|
||||||
|
val flavourOfPrefs = flavour.value
|
||||||
|
if (flavour.value != BuildConfig.FLAVOR) {
|
||||||
|
flavour.status = PrefsStatus.WARN
|
||||||
|
flavour.info = resourceHelper.gs(R.string.metadata_warning_different_flavour, flavourOfPrefs, BuildConfig.FLAVOR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
meta[PrefsMetadataKey.DEVICE_MODEL]?.let { model ->
|
||||||
|
if (model.value != getCurrentDeviceModelString()) {
|
||||||
|
model.status = PrefsStatus.WARN
|
||||||
|
model.info = resourceHelper.gs(R.string.metadata_warning_different_device)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
meta[PrefsMetadataKey.CREATED_AT]?.let { createdAt ->
|
||||||
|
try {
|
||||||
|
val date1 = DateTime.parse(createdAt.value);
|
||||||
|
val date2 = DateTime.now()
|
||||||
|
|
||||||
|
val daysOld = Days.daysBetween(date1.toLocalDate(), date2.toLocalDate()).getDays()
|
||||||
|
|
||||||
|
if (daysOld > IMPORT_AGE_NOT_YET_OLD_DAYS) {
|
||||||
|
createdAt.status = PrefsStatus.WARN
|
||||||
|
createdAt.info = resourceHelper.gs(R.string.metadata_warning_old_export, daysOld.toString())
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
createdAt.status = PrefsStatus.WARN
|
||||||
|
createdAt.info = resourceHelper.gs(R.string.metadata_warning_date_format)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return meta
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkIfImportIsOk(prefs: Prefs): Boolean {
|
||||||
|
var importOk = true
|
||||||
|
|
||||||
|
for ((_, value) in prefs.metadata) {
|
||||||
|
if (value.status == PrefsStatus.ERROR)
|
||||||
|
importOk = false;
|
||||||
|
}
|
||||||
|
return importOk
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun restartAppAfterImport(context: Context) {
|
||||||
|
sp.putBoolean(R.string.key_setupwizard_processed, true)
|
||||||
|
show(context, resourceHelper.gs(R.string.setting_imported), resourceHelper.gs(R.string.restartingapp), Runnable {
|
||||||
|
log.debug(TAG, "Exiting")
|
||||||
|
rxBus.send(EventAppExit())
|
||||||
|
if (context is Activity) {
|
||||||
|
context.finish()
|
||||||
|
}
|
||||||
|
System.runFinalization()
|
||||||
|
System.exit(0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ class MaintenanceFragment : DaggerFragment() {
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
|
||||||
@Inject lateinit var foodPlugin: FoodPlugin
|
@Inject lateinit var foodPlugin: FoodPlugin
|
||||||
|
@Inject lateinit var importExportPrefs: ImportExportPrefs
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
return inflater.inflate(R.layout.maintenance_fragment, container, false)
|
return inflater.inflate(R.layout.maintenance_fragment, container, false)
|
||||||
|
@ -45,13 +46,13 @@ class MaintenanceFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
nav_export.setOnClickListener {
|
nav_export.setOnClickListener {
|
||||||
// start activity for checking permissions...
|
// start activity for checking permissions...
|
||||||
ImportExportPrefs.verifyStoragePermissions(this)
|
importExportPrefs.verifyStoragePermissions(this)
|
||||||
ImportExportPrefs.exportSharedPreferences(this)
|
importExportPrefs.exportSharedPreferences(this)
|
||||||
}
|
}
|
||||||
nav_import.setOnClickListener {
|
nav_import.setOnClickListener {
|
||||||
// start activity for checking permissions...
|
// start activity for checking permissions...
|
||||||
ImportExportPrefs.verifyStoragePermissions(this)
|
importExportPrefs.verifyStoragePermissions(this)
|
||||||
ImportExportPrefs.importSharedPreferences(this)
|
importExportPrefs.importSharedPreferences(this)
|
||||||
}
|
}
|
||||||
nav_logsettings.setOnClickListener { startActivity(Intent(activity, LogSettingActivity::class.java)) }
|
nav_logsettings.setOnClickListener { startActivity(Intent(activity, LogSettingActivity::class.java)) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import androidx.preference.SwitchPreference
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.BuildConfig
|
import info.nightscout.androidaps.BuildConfig
|
||||||
import info.nightscout.androidaps.Config
|
import info.nightscout.androidaps.Config
|
||||||
|
@ -16,6 +18,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
|
||||||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import info.nightscout.androidaps.utils.textValidator.ValidatingEditTextPreference
|
||||||
import java.io.*
|
import java.io.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
|
@ -203,4 +206,13 @@ class MaintenancePlugin @Inject constructor(
|
||||||
emailIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
emailIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
return emailIntent
|
return emailIntent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun preprocessPreferences(preferenceFragment: PreferenceFragmentCompat) {
|
||||||
|
super.preprocessPreferences(preferenceFragment)
|
||||||
|
val encryptSwitch = preferenceFragment.findPreference(resourceHelper.gs(R.string.key_maintenance_encrypt_exported_prefs)) as SwitchPreference?
|
||||||
|
?: return
|
||||||
|
encryptSwitch.isVisible = buildHelper.isEngineeringMode()
|
||||||
|
encryptSwitch.isEnabled = buildHelper.isEngineeringMode()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package info.nightscout.androidaps.plugins.general.maintenance.formats
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.storage.Storage
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileNotFoundException
|
||||||
|
import java.io.IOException
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class ClassicPrefsFormat @Inject constructor(
|
||||||
|
private var resourceHelper: ResourceHelper,
|
||||||
|
private var storage: Storage
|
||||||
|
) : PrefsFormat {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val FORMAT_KEY = "aaps_old"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun savePreferences(file: File, prefs: Prefs, masterPassword: String?) {
|
||||||
|
try {
|
||||||
|
val contents = prefs.values.entries.joinToString("\n") { entry ->
|
||||||
|
"${entry.key}::${entry.value}"
|
||||||
|
}
|
||||||
|
storage.putFileContents(file, contents)
|
||||||
|
} catch (e: FileNotFoundException) {
|
||||||
|
throw PrefFileNotFoundError(file.absolutePath)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw PrefIOError(file.absolutePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadPreferences(file: File, masterPassword: String?): Prefs {
|
||||||
|
var lineParts: Array<String>
|
||||||
|
val entries: MutableMap<String, String> = mutableMapOf()
|
||||||
|
val metadata: MutableMap<PrefsMetadataKey, PrefMetadata> = mutableMapOf()
|
||||||
|
try {
|
||||||
|
|
||||||
|
val rawLines = storage.getFileContents(file).split("\n")
|
||||||
|
rawLines.forEach { line ->
|
||||||
|
lineParts = line.split("::").toTypedArray()
|
||||||
|
if (lineParts.size == 2) {
|
||||||
|
entries[lineParts[0]] = lineParts[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata[PrefsMetadataKey.FILE_FORMAT] = PrefMetadata(FORMAT_KEY, PrefsStatus.WARN, resourceHelper.gs(R.string.metadata_warning_outdated_format))
|
||||||
|
|
||||||
|
return Prefs(entries, metadata)
|
||||||
|
|
||||||
|
} catch (e: FileNotFoundException) {
|
||||||
|
throw PrefFileNotFoundError(file.absolutePath)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw PrefIOError(file.absolutePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,225 @@
|
||||||
|
package info.nightscout.androidaps.plugins.general.maintenance.formats
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.utils.CryptoUtil
|
||||||
|
import info.nightscout.androidaps.utils.hexStringToByteArray
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.storage.Storage
|
||||||
|
import info.nightscout.androidaps.utils.toHex
|
||||||
|
import org.json.JSONException
|
||||||
|
import org.json.JSONObject
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileNotFoundException
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class EncryptedPrefsFormat @Inject constructor(
|
||||||
|
private var resourceHelper: ResourceHelper,
|
||||||
|
private var storage: Storage
|
||||||
|
) : PrefsFormat {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val FORMAT_KEY_ENC = "aaps_encrypted"
|
||||||
|
val FORMAT_KEY_NOENC = "aaps_structured"
|
||||||
|
|
||||||
|
private val KEY_CONSCIENCE = "if you remove/change this, please make sure you know the consequences!"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun savePreferences(file: File, prefs: Prefs, masterPassword: String?) {
|
||||||
|
|
||||||
|
val container = JSONObject()
|
||||||
|
val content = JSONObject()
|
||||||
|
val meta = JSONObject()
|
||||||
|
|
||||||
|
val encStatus = prefs.metadata[PrefsMetadataKey.ENCRYPTION]?.status ?: PrefsStatus.OK
|
||||||
|
var encrypted = encStatus == PrefsStatus.OK && masterPassword != null
|
||||||
|
|
||||||
|
try {
|
||||||
|
for ((key, value) in prefs.values.toSortedMap()) {
|
||||||
|
content.put(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((metaKey, metaEntry) in prefs.metadata) {
|
||||||
|
if (metaKey == PrefsMetadataKey.FILE_FORMAT)
|
||||||
|
continue;
|
||||||
|
if (metaKey == PrefsMetadataKey.ENCRYPTION)
|
||||||
|
continue;
|
||||||
|
meta.put(metaKey.key, metaEntry.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
container.put(PrefsMetadataKey.FILE_FORMAT.key, if (encrypted) FORMAT_KEY_ENC else FORMAT_KEY_NOENC);
|
||||||
|
container.put("metadata", meta)
|
||||||
|
|
||||||
|
val security = JSONObject()
|
||||||
|
security.put("file_hash", "--to-be-calculated--")
|
||||||
|
var encodedContent = ""
|
||||||
|
|
||||||
|
if (encrypted) {
|
||||||
|
val salt = CryptoUtil.mineSalt()
|
||||||
|
val rawContent = content.toString()
|
||||||
|
val contentAttempt = CryptoUtil.encrypt(masterPassword!!, salt, rawContent)
|
||||||
|
if (contentAttempt != null) {
|
||||||
|
encodedContent = contentAttempt
|
||||||
|
security.put("algorithm", "v1")
|
||||||
|
security.put("salt", salt.toHex())
|
||||||
|
security.put("content_hash", CryptoUtil.sha256(rawContent))
|
||||||
|
} else {
|
||||||
|
// fallback when encryption does not work
|
||||||
|
encrypted = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!encrypted) {
|
||||||
|
security.put("algorithm", "none")
|
||||||
|
}
|
||||||
|
|
||||||
|
container.put("security", security)
|
||||||
|
container.put("content", if (encrypted) encodedContent else content)
|
||||||
|
|
||||||
|
var fileContents = container.toString(2)
|
||||||
|
val fileHash = CryptoUtil.hmac256(fileContents, KEY_CONSCIENCE)
|
||||||
|
|
||||||
|
fileContents = fileContents.replace(Regex("(\\\"file_hash\\\"\\s*\\:\\s*\\\")(--to-be-calculated--)(\\\")"), "$1" + fileHash + "$3")
|
||||||
|
|
||||||
|
storage.putFileContents(file, fileContents)
|
||||||
|
|
||||||
|
} catch (e: FileNotFoundException) {
|
||||||
|
throw PrefFileNotFoundError(file.absolutePath)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw PrefIOError(file.absolutePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadPreferences(file: File, masterPassword: String?): Prefs {
|
||||||
|
|
||||||
|
val entries: MutableMap<String, String> = mutableMapOf()
|
||||||
|
val metadata: MutableMap<PrefsMetadataKey, PrefMetadata> = mutableMapOf()
|
||||||
|
val issues = LinkedList<String>()
|
||||||
|
try {
|
||||||
|
|
||||||
|
val jsonBody = storage.getFileContents(file)
|
||||||
|
val fileContents = jsonBody.replace(Regex("(?is)(\\\"file_hash\\\"\\s*\\:\\s*\\\")([^\"]*)(\\\")"), "$1--to-be-calculated--$3")
|
||||||
|
val calculatedFileHash = CryptoUtil.hmac256(fileContents, KEY_CONSCIENCE)
|
||||||
|
val container = JSONObject(jsonBody)
|
||||||
|
|
||||||
|
if (container.has(PrefsMetadataKey.FILE_FORMAT.key) && container.has("security") && container.has("content") && container.has("metadata")) {
|
||||||
|
val fileFormat = container.getString(PrefsMetadataKey.FILE_FORMAT.key)
|
||||||
|
|
||||||
|
if ((fileFormat != FORMAT_KEY_ENC) && (fileFormat != FORMAT_KEY_NOENC)) {
|
||||||
|
throw PrefFormatError("Unsupported file format: " + fileFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
val meta = container.getJSONObject("metadata")
|
||||||
|
val security = container.getJSONObject("security")
|
||||||
|
|
||||||
|
metadata[PrefsMetadataKey.FILE_FORMAT] = PrefMetadata(fileFormat, PrefsStatus.OK)
|
||||||
|
for (key in meta.keys()) {
|
||||||
|
val metaKey = PrefsMetadataKey.fromKey(key)
|
||||||
|
if (metaKey != null) {
|
||||||
|
metadata[metaKey] = PrefMetadata(meta.getString(key), PrefsStatus.OK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val encrypted = fileFormat == FORMAT_KEY_ENC
|
||||||
|
var secure: PrefsStatus = PrefsStatus.OK
|
||||||
|
var decryptedOk = false
|
||||||
|
var contentJsonObj: JSONObject? = null
|
||||||
|
var insecurityReason = resourceHelper.gs(R.string.prefdecrypt_settings_tampered)
|
||||||
|
|
||||||
|
if (security.has("file_hash")) {
|
||||||
|
if (calculatedFileHash != security.getString("file_hash")) {
|
||||||
|
secure = PrefsStatus.ERROR
|
||||||
|
issues.add(resourceHelper.gs(R.string.prefdecrypt_issue_modified))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
secure = PrefsStatus.ERROR
|
||||||
|
issues.add(resourceHelper.gs(R.string.prefdecrypt_issue_missing_file_hash))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encrypted) {
|
||||||
|
if (security.has("algorithm") && security.get("algorithm") == "v1") {
|
||||||
|
if (security.has("salt") && security.has("content_hash")) {
|
||||||
|
|
||||||
|
val salt = security.getString("salt").hexStringToByteArray()
|
||||||
|
val decrypted = CryptoUtil.decrypt(masterPassword!!, salt, container.getString("content"))
|
||||||
|
|
||||||
|
if (decrypted != null) {
|
||||||
|
try {
|
||||||
|
val contentHash = CryptoUtil.sha256(decrypted)
|
||||||
|
|
||||||
|
if (contentHash == security.getString("content_hash")) {
|
||||||
|
contentJsonObj = JSONObject(decrypted)
|
||||||
|
decryptedOk = true
|
||||||
|
} else {
|
||||||
|
secure = PrefsStatus.ERROR
|
||||||
|
issues.add(resourceHelper.gs(R.string.prefdecrypt_issue_modified))
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e: JSONException) {
|
||||||
|
secure = PrefsStatus.ERROR
|
||||||
|
issues.add(resourceHelper.gs(R.string.prefdecrypt_issue_parsing))
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
secure = PrefsStatus.ERROR
|
||||||
|
issues.add(resourceHelper.gs(R.string.prefdecrypt_issue_wrong_pass))
|
||||||
|
insecurityReason = resourceHelper.gs(R.string.prefdecrypt_wrong_password)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
secure = PrefsStatus.ERROR
|
||||||
|
issues.add(resourceHelper.gs(R.string.prefdecrypt_issue_wrong_format))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
secure = PrefsStatus.ERROR
|
||||||
|
issues.add(resourceHelper.gs(R.string.prefdecrypt_issue_wrong_algorithm))
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (secure == PrefsStatus.OK) {
|
||||||
|
secure = PrefsStatus.WARN
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(security.has("algorithm") && security.get("algorithm") == "none")) {
|
||||||
|
secure = PrefsStatus.ERROR
|
||||||
|
issues.add(resourceHelper.gs(R.string.prefdecrypt_issue_wrong_algorithm))
|
||||||
|
}
|
||||||
|
|
||||||
|
contentJsonObj = container.getJSONObject("content")
|
||||||
|
decryptedOk = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decryptedOk && contentJsonObj != null) {
|
||||||
|
for (key in contentJsonObj.keys()) {
|
||||||
|
entries.put(key, contentJsonObj[key].toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val issuesStr: String? = if (issues.size > 0) issues.joinToString("\n") else null
|
||||||
|
val encryptionDescStr = if (encrypted) {
|
||||||
|
if (secure == PrefsStatus.OK) resourceHelper.gs(R.string.prefdecrypt_settings_secure) else insecurityReason
|
||||||
|
} else {
|
||||||
|
if (secure != PrefsStatus.ERROR) resourceHelper.gs(R.string.prefdecrypt_settings_unencrypted) else resourceHelper.gs(R.string.prefdecrypt_settings_tampered)
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata[PrefsMetadataKey.ENCRYPTION] = PrefMetadata(encryptionDescStr, secure, issuesStr)
|
||||||
|
} else {
|
||||||
|
metadata[PrefsMetadataKey.FILE_FORMAT] = PrefMetadata(resourceHelper.gs(R.string.prefdecrypt_wrong_json), PrefsStatus.ERROR)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Prefs(entries, metadata)
|
||||||
|
|
||||||
|
} catch (e: FileNotFoundException) {
|
||||||
|
throw PrefFileNotFoundError(file.absolutePath)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
throw PrefIOError(file.absolutePath)
|
||||||
|
} catch (e: JSONException) {
|
||||||
|
throw PrefFormatError("Mallformed preferences JSON file: " + e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package info.nightscout.androidaps.plugins.general.maintenance.formats
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
enum class PrefsMetadataKey(val key: String, @DrawableRes val icon:Int, @StringRes val label:Int) {
|
||||||
|
|
||||||
|
FILE_FORMAT("format", R.drawable.ic_meta_format, R.string.metadata_label_format),
|
||||||
|
CREATED_AT("created_at", R.drawable.ic_meta_date, R.string.metadata_label_created_at),
|
||||||
|
AAPS_VERSION("aaps_version", R.drawable.ic_meta_version, R.string.metadata_label_aaps_version),
|
||||||
|
AAPS_FLAVOUR("aaps_flavour", R.drawable.ic_meta_flavour, R.string.metadata_label_aaps_flavour),
|
||||||
|
DEVICE_NAME("device_name", R.drawable.ic_meta_name, R.string.metadata_label_device_name),
|
||||||
|
DEVICE_MODEL("device_model", R.drawable.ic_meta_model, R.string.metadata_label_device_model),
|
||||||
|
ENCRYPTION("encryption", R.drawable.ic_meta_encryption, R.string.metadata_label_encryption);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val keyToEnumMap = HashMap<String, PrefsMetadataKey>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
for (value in values()) {
|
||||||
|
keyToEnumMap.put(value.key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fromKey(key: String): PrefsMetadataKey? {
|
||||||
|
if (keyToEnumMap.containsKey(key)) {
|
||||||
|
return keyToEnumMap.get(key)
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun formatForDisplay(context: Context, value:String): String {
|
||||||
|
return when (this) {
|
||||||
|
FILE_FORMAT -> when (value) {
|
||||||
|
ClassicPrefsFormat.FORMAT_KEY -> context.getString(R.string.metadata_format_old)
|
||||||
|
EncryptedPrefsFormat.FORMAT_KEY_ENC -> context.getString(R.string.metadata_format_new)
|
||||||
|
EncryptedPrefsFormat.FORMAT_KEY_NOENC -> context.getString(R.string.metadata_format_debug)
|
||||||
|
else -> context.getString(R.string.metadata_format_other)
|
||||||
|
}
|
||||||
|
CREATED_AT -> value.replace("T", " ").replace("Z", " (UTC)")
|
||||||
|
else -> value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
data class PrefMetadata(var value : String, var status : PrefsStatus, var info : String? = null)
|
||||||
|
|
||||||
|
data class Prefs(val values : Map<String, String>, var metadata : Map<PrefsMetadataKey, PrefMetadata>)
|
||||||
|
|
||||||
|
interface PrefsFormat {
|
||||||
|
fun savePreferences(file: File, prefs: Prefs, masterPassword: String? = null)
|
||||||
|
fun loadPreferences(file: File, masterPassword: String? = null) : Prefs
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class PrefsStatus(@DrawableRes val icon:Int) {
|
||||||
|
OK(R.drawable.ic_meta_ok),
|
||||||
|
WARN(R.drawable.ic_meta_warning),
|
||||||
|
ERROR(R.drawable.ic_meta_error),
|
||||||
|
UNKNOWN(R.drawable.ic_meta_error),
|
||||||
|
DISABLED(R.drawable.ic_meta_error)
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrefFileNotFoundError(message: String) : Exception(message)
|
||||||
|
class PrefIOError(message: String) : Exception(message)
|
||||||
|
class PrefFormatError(message: String) : Exception(message)
|
|
@ -71,7 +71,7 @@ public class NSClientPlugin extends PluginBase {
|
||||||
|
|
||||||
public NSClientService nsClientService = null;
|
public NSClientService nsClientService = null;
|
||||||
|
|
||||||
private NsClientReceiverDelegate nsClientReceiverDelegate = new NsClientReceiverDelegate();
|
private NsClientReceiverDelegate nsClientReceiverDelegate;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public NSClientPlugin(
|
public NSClientPlugin(
|
||||||
|
@ -80,7 +80,8 @@ public class NSClientPlugin extends PluginBase {
|
||||||
RxBusWrapper rxBus,
|
RxBusWrapper rxBus,
|
||||||
ResourceHelper resourceHelper,
|
ResourceHelper resourceHelper,
|
||||||
Context context,
|
Context context,
|
||||||
SP sp
|
SP sp,
|
||||||
|
NsClientReceiverDelegate nsClientReceiverDelegate
|
||||||
) {
|
) {
|
||||||
super(new PluginDescription()
|
super(new PluginDescription()
|
||||||
.mainType(PluginType.GENERAL)
|
.mainType(PluginType.GENERAL)
|
||||||
|
@ -97,6 +98,7 @@ public class NSClientPlugin extends PluginBase {
|
||||||
this.resourceHelper = resourceHelper;
|
this.resourceHelper = resourceHelper;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.sp = sp;
|
this.sp = sp;
|
||||||
|
this.nsClientReceiverDelegate = nsClientReceiverDelegate;
|
||||||
|
|
||||||
if (Config.NSCLIENT) {
|
if (Config.NSCLIENT) {
|
||||||
getPluginDescription().alwaysEnabled(true).visibleByDefault(true);
|
getPluginDescription().alwaysEnabled(true).visibleByDefault(true);
|
||||||
|
|
|
@ -1,50 +1,55 @@
|
||||||
package info.nightscout.androidaps.plugins.general.nsclient;
|
package info.nightscout.androidaps.plugins.general.nsclient;
|
||||||
|
|
||||||
import android.content.Context;
|
import javax.inject.Inject;
|
||||||
import android.content.Intent;
|
import javax.inject.Singleton;
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.wifi.WifiManager;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.MainApp;
|
|
||||||
import info.nightscout.androidaps.R;
|
import info.nightscout.androidaps.R;
|
||||||
import info.nightscout.androidaps.events.EventChargingState;
|
import info.nightscout.androidaps.events.EventChargingState;
|
||||||
import info.nightscout.androidaps.events.EventNetworkChange;
|
import info.nightscout.androidaps.events.EventNetworkChange;
|
||||||
import info.nightscout.androidaps.events.EventPreferenceChange;
|
import info.nightscout.androidaps.events.EventPreferenceChange;
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||||
import info.nightscout.androidaps.receivers.ChargingStateReceiver;
|
import info.nightscout.androidaps.receivers.ReceiverStatusStore;
|
||||||
import info.nightscout.androidaps.receivers.NetworkChangeReceiver;
|
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||||
import info.nightscout.androidaps.utils.SP;
|
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
class NsClientReceiverDelegate {
|
class NsClientReceiverDelegate {
|
||||||
|
|
||||||
private boolean allowedChargingState = true;
|
private boolean allowedChargingState = true;
|
||||||
private boolean allowedNetworkState = true;
|
private boolean allowedNetworkState = true;
|
||||||
boolean allowed = true;
|
boolean allowed = true;
|
||||||
|
|
||||||
|
private RxBusWrapper rxBus;
|
||||||
|
private ResourceHelper resourceHelper;
|
||||||
|
private SP sp;
|
||||||
|
private ReceiverStatusStore receiverStatusStore;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public NsClientReceiverDelegate(
|
||||||
|
RxBusWrapper rxBus,
|
||||||
|
ResourceHelper resourceHelper,
|
||||||
|
SP sp,
|
||||||
|
ReceiverStatusStore receiverStatusStore
|
||||||
|
) {
|
||||||
|
this.rxBus = rxBus;
|
||||||
|
this.resourceHelper = resourceHelper;
|
||||||
|
this.sp = sp;
|
||||||
|
this.receiverStatusStore = receiverStatusStore;
|
||||||
|
}
|
||||||
|
|
||||||
void grabReceiversState() {
|
void grabReceiversState() {
|
||||||
Context context = MainApp.instance().getApplicationContext();
|
|
||||||
|
|
||||||
EventNetworkChange event = NetworkChangeReceiver.grabNetworkStatus(context);
|
|
||||||
if (event != null) RxBus.Companion.getINSTANCE().send(event);
|
|
||||||
|
|
||||||
EventChargingState eventChargingState = ChargingStateReceiver.grabChargingState(context);
|
|
||||||
if (eventChargingState != null) RxBus.Companion.getINSTANCE().send(eventChargingState);
|
|
||||||
|
|
||||||
|
receiverStatusStore.updateNetworkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onStatusEvent(EventPreferenceChange ev) {
|
void onStatusEvent(EventPreferenceChange ev) {
|
||||||
if (ev.isChanged(MainApp.resources(), R.string.key_ns_wifionly) ||
|
if (ev.isChanged(resourceHelper, R.string.key_ns_wifionly) ||
|
||||||
ev.isChanged(MainApp.resources(), R.string.key_ns_wifi_ssids) ||
|
ev.isChanged(resourceHelper, R.string.key_ns_wifi_ssids) ||
|
||||||
ev.isChanged(MainApp.resources(), R.string.key_ns_allowroaming)
|
ev.isChanged(resourceHelper, R.string.key_ns_allowroaming)
|
||||||
) {
|
) {
|
||||||
EventNetworkChange event = NetworkChangeReceiver.grabNetworkStatus(MainApp.instance().getApplicationContext());
|
receiverStatusStore.updateNetworkStatus();
|
||||||
if (event != null)
|
} else if (ev.isChanged(resourceHelper, R.string.key_ns_chargingonly)) {
|
||||||
RxBus.Companion.getINSTANCE().send(event);
|
receiverStatusStore.broadcastChargingState();
|
||||||
} else if (ev.isChanged(MainApp.resources(), R.string.key_ns_chargingonly)) {
|
|
||||||
EventChargingState event = ChargingStateReceiver.grabChargingState(MainApp.instance().getApplicationContext());
|
|
||||||
if (event != null)
|
|
||||||
RxBus.Companion.getINSTANCE().send(event);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,12 +75,12 @@ class NsClientReceiverDelegate {
|
||||||
boolean newAllowedState = allowedChargingState && allowedNetworkState;
|
boolean newAllowedState = allowedChargingState && allowedNetworkState;
|
||||||
if (newAllowedState != allowed) {
|
if (newAllowedState != allowed) {
|
||||||
allowed = newAllowedState;
|
allowed = newAllowedState;
|
||||||
RxBus.Companion.getINSTANCE().send(new EventPreferenceChange(MainApp.gs(R.string.key_nsclientinternal_paused)));
|
rxBus.send(new EventPreferenceChange(resourceHelper.gs(R.string.key_nsclientinternal_paused)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean calculateStatus(final EventChargingState ev) {
|
boolean calculateStatus(final EventChargingState ev) {
|
||||||
boolean chargingOnly = SP.getBoolean(R.string.key_ns_chargingonly, false);
|
boolean chargingOnly = sp.getBoolean(R.string.key_ns_chargingonly, false);
|
||||||
boolean newAllowedState = true;
|
boolean newAllowedState = true;
|
||||||
|
|
||||||
if (!ev.isCharging() && chargingOnly) {
|
if (!ev.isCharging() && chargingOnly) {
|
||||||
|
@ -86,9 +91,9 @@ class NsClientReceiverDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean calculateStatus(final EventNetworkChange ev) {
|
boolean calculateStatus(final EventNetworkChange ev) {
|
||||||
boolean wifiOnly = SP.getBoolean(R.string.key_ns_wifionly, false);
|
boolean wifiOnly = sp.getBoolean(R.string.key_ns_wifionly, false);
|
||||||
String allowedSSIDs = SP.getString(R.string.key_ns_wifi_ssids, "");
|
String allowedSSIDs = sp.getString(R.string.key_ns_wifi_ssids, "");
|
||||||
boolean allowRoaming = SP.getBoolean(R.string.key_ns_allowroaming, true);
|
boolean allowRoaming = sp.getBoolean(R.string.key_ns_allowroaming, true);
|
||||||
|
|
||||||
boolean newAllowedState = true;
|
boolean newAllowedState = true;
|
||||||
|
|
||||||
|
|
|
@ -1008,6 +1008,63 @@ public class OverviewFragment extends DaggerFragment implements View.OnClickList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void processInsulinCarbsButtonsVisibility() {
|
||||||
|
BgReading lastBG = iobCobCalculatorPlugin.lastBg();
|
||||||
|
|
||||||
|
final PumpInterface pump = activePlugin.getActivePump();
|
||||||
|
|
||||||
|
final Profile profile = profileFunction.getProfile();
|
||||||
|
final String profileName = profileFunction.getProfileName();
|
||||||
|
|
||||||
|
// QuickWizard button
|
||||||
|
QuickWizardEntry quickWizardEntry = quickWizard.getActive();
|
||||||
|
if (quickWizardEntry != null && lastBG != null && profile != null && pump.isInitialized() && !pump.isSuspended()) {
|
||||||
|
quickWizardButton.setVisibility(View.VISIBLE);
|
||||||
|
String text = quickWizardEntry.buttonText() + "\n" + DecimalFormatter.to0Decimal(quickWizardEntry.carbs()) + "g";
|
||||||
|
BolusWizard wizard = quickWizardEntry.doCalc(profile, profileName, lastBG, false);
|
||||||
|
text += " " + DecimalFormatter.toPumpSupportedBolus(wizard.getCalculatedTotalInsulin(), pump) + "U";
|
||||||
|
quickWizardButton.setText(text);
|
||||||
|
if (wizard.getCalculatedTotalInsulin() <= 0)
|
||||||
|
quickWizardButton.setVisibility(View.GONE);
|
||||||
|
} else
|
||||||
|
quickWizardButton.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
// **** Various treatment buttons ****
|
||||||
|
if (carbsButton != null) {
|
||||||
|
if ((!activePlugin.getActivePump().getPumpDescription().storesCarbInfo || (pump.isInitialized() && !pump.isSuspended())) &&
|
||||||
|
profile != null &&
|
||||||
|
sp.getBoolean(R.string.key_show_carbs_button, true))
|
||||||
|
carbsButton.setVisibility(View.VISIBLE);
|
||||||
|
else
|
||||||
|
carbsButton.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (treatmentButton != null) {
|
||||||
|
if (pump.isInitialized() && !pump.isSuspended() &&
|
||||||
|
profile != null &&
|
||||||
|
sp.getBoolean(R.string.key_show_treatment_button, false))
|
||||||
|
treatmentButton.setVisibility(View.VISIBLE);
|
||||||
|
else
|
||||||
|
treatmentButton.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
if (wizardButton != null) {
|
||||||
|
if (pump.isInitialized() && !pump.isSuspended() &&
|
||||||
|
profile != null &&
|
||||||
|
sp.getBoolean(R.string.key_show_wizard_button, true))
|
||||||
|
wizardButton.setVisibility(View.VISIBLE);
|
||||||
|
else
|
||||||
|
wizardButton.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
if (insulinButton != null) {
|
||||||
|
if (pump.isInitialized() && !pump.isSuspended() &&
|
||||||
|
profile != null &&
|
||||||
|
sp.getBoolean(R.string.key_show_insulin_button, true))
|
||||||
|
insulinButton.setVisibility(View.VISIBLE);
|
||||||
|
else
|
||||||
|
insulinButton.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void scheduleUpdateGUI(final String from) {
|
private void scheduleUpdateGUI(final String from) {
|
||||||
class UpdateRunnable implements Runnable {
|
class UpdateRunnable implements Runnable {
|
||||||
public void run() {
|
public void run() {
|
||||||
|
@ -1060,7 +1117,6 @@ public class OverviewFragment extends DaggerFragment implements View.OnClickList
|
||||||
|
|
||||||
final Profile profile = profileFunction.getProfile();
|
final Profile profile = profileFunction.getProfile();
|
||||||
if (profile == null) return;
|
if (profile == null) return;
|
||||||
final String profileName = profileFunction.getProfileName();
|
|
||||||
|
|
||||||
final String units = profileFunction.getUnits();
|
final String units = profileFunction.getUnits();
|
||||||
final double lowLine = defaultValueHelper.determineLowLine();
|
final double lowLine = defaultValueHelper.determineLowLine();
|
||||||
|
@ -1234,53 +1290,7 @@ public class OverviewFragment extends DaggerFragment implements View.OnClickList
|
||||||
activeProfileView.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault));
|
activeProfileView.setTextColor(resourceHelper.gc(R.color.ribbonTextDefault));
|
||||||
}
|
}
|
||||||
|
|
||||||
// QuickWizard button
|
processInsulinCarbsButtonsVisibility();
|
||||||
QuickWizardEntry quickWizardEntry = quickWizard.getActive();
|
|
||||||
if (quickWizardEntry != null && lastBG != null && pump.isInitialized() && !pump.isSuspended()) {
|
|
||||||
quickWizardButton.setVisibility(View.VISIBLE);
|
|
||||||
String text = quickWizardEntry.buttonText() + "\n" + DecimalFormatter.to0Decimal(quickWizardEntry.carbs()) + "g";
|
|
||||||
BolusWizard wizard = quickWizardEntry.doCalc(profile, profileName, lastBG, false);
|
|
||||||
text += " " + DecimalFormatter.toPumpSupportedBolus(wizard.getCalculatedTotalInsulin(), pump) + "U";
|
|
||||||
quickWizardButton.setText(text);
|
|
||||||
if (wizard.getCalculatedTotalInsulin() <= 0)
|
|
||||||
quickWizardButton.setVisibility(View.GONE);
|
|
||||||
} else
|
|
||||||
quickWizardButton.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
// **** Various treatment buttons ****
|
|
||||||
if (carbsButton != null) {
|
|
||||||
if (sp.getBoolean(R.string.key_show_carbs_button, true)
|
|
||||||
&& (!activePlugin.getActivePump().getPumpDescription().storesCarbInfo ||
|
|
||||||
(pump.isInitialized() && !pump.isSuspended()))) {
|
|
||||||
carbsButton.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
carbsButton.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pump.isInitialized() && !pump.isSuspended()) {
|
|
||||||
if (treatmentButton != null) {
|
|
||||||
if (sp.getBoolean(R.string.key_show_treatment_button, false)) {
|
|
||||||
treatmentButton.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
treatmentButton.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pump.isInitialized() && !pump.isSuspended() && wizardButton != null) {
|
|
||||||
if (sp.getBoolean(R.string.key_show_wizard_button, true)) {
|
|
||||||
wizardButton.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
wizardButton.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pump.isInitialized() && !pump.isSuspended() && insulinButton != null) {
|
|
||||||
if (sp.getBoolean(R.string.key_show_insulin_button, true)) {
|
|
||||||
insulinButton.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
insulinButton.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// **** BG value ****
|
// **** BG value ****
|
||||||
if (lastBG == null) { //left this here as it seems you want to exit at this point if it is null...
|
if (lastBG == null) { //left this here as it seems you want to exit at this point if it is null...
|
||||||
|
@ -1453,7 +1463,7 @@ public class OverviewFragment extends DaggerFragment implements View.OnClickList
|
||||||
|
|
||||||
// add basal data
|
// add basal data
|
||||||
if (pump.getPumpDescription().isTempBasalCapable && sp.getBoolean("showbasals", true)) {
|
if (pump.getPumpDescription().isTempBasalCapable && sp.getBoolean("showbasals", true)) {
|
||||||
graphData.addBasals(fromTime, now, lowLine / graphData.maxY / 1.2d);
|
graphData.addBasals(fromTime, now, lowLine / graphData.getMaxY() / 1.2d);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add target line
|
// add target line
|
||||||
|
|
|
@ -1,726 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.general.overview.graphData;
|
|
||||||
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.graphics.DashPathEffect;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
|
|
||||||
import com.jjoe64.graphview.GraphView;
|
|
||||||
import com.jjoe64.graphview.series.BarGraphSeries;
|
|
||||||
import com.jjoe64.graphview.series.DataPoint;
|
|
||||||
import com.jjoe64.graphview.series.LineGraphSeries;
|
|
||||||
import com.jjoe64.graphview.series.Series;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import dagger.android.HasAndroidInjector;
|
|
||||||
import info.nightscout.androidaps.Constants;
|
|
||||||
import info.nightscout.androidaps.MainApp;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.data.IobTotal;
|
|
||||||
import info.nightscout.androidaps.data.Profile;
|
|
||||||
import info.nightscout.androidaps.db.BgReading;
|
|
||||||
import info.nightscout.androidaps.db.CareportalEvent;
|
|
||||||
import info.nightscout.androidaps.db.ExtendedBolus;
|
|
||||||
import info.nightscout.androidaps.db.ProfileSwitch;
|
|
||||||
import info.nightscout.androidaps.db.TempTarget;
|
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
|
||||||
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.APSResult;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults;
|
|
||||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.AreaGraphSeries;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DataPointWithLabelInterface;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.DoubleDataPoint;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.FixedLineGraphSeries;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.PointsWithLabelGraphSeries;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.Scale;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.ScaledDataPoint;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.TimeAsXAxisLabelFormatter;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensData;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.BasalData;
|
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
|
|
||||||
import info.nightscout.androidaps.plugins.treatments.Treatment;
|
|
||||||
import info.nightscout.androidaps.utils.DecimalFormatter;
|
|
||||||
import info.nightscout.androidaps.utils.Round;
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by mike on 18.10.2017.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class GraphData {
|
|
||||||
|
|
||||||
@Inject AAPSLogger aapsLogger;
|
|
||||||
@Inject ProfileFunction profileFunction;
|
|
||||||
@Inject ResourceHelper resourceHelper;
|
|
||||||
@Inject ActivePluginProvider activePlugin;
|
|
||||||
|
|
||||||
private GraphView graph;
|
|
||||||
public double maxY = Double.MIN_VALUE;
|
|
||||||
private double minY = Double.MAX_VALUE;
|
|
||||||
private List<BgReading> bgReadingsArray;
|
|
||||||
private String units;
|
|
||||||
private List<Series> series = new ArrayList<>();
|
|
||||||
private TreatmentsInterface treatmentsPlugin;
|
|
||||||
|
|
||||||
|
|
||||||
private IobCobCalculatorPlugin iobCobCalculatorPlugin; // Cannot be injected: HistoryBrowser
|
|
||||||
|
|
||||||
public GraphData(HasAndroidInjector injector, GraphView graph, IobCobCalculatorPlugin iobCobCalculatorPlugin) {
|
|
||||||
injector.androidInjector().inject(this);
|
|
||||||
units = profileFunction.getUnits();
|
|
||||||
this.graph = graph;
|
|
||||||
this.iobCobCalculatorPlugin = iobCobCalculatorPlugin;
|
|
||||||
treatmentsPlugin = activePlugin.getActiveTreatments();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addBgReadings(long fromTime, long toTime, double lowLine, double highLine, List<BgReading> predictions) {
|
|
||||||
double maxBgValue = Double.MIN_VALUE;
|
|
||||||
//bgReadingsArray = MainApp.getDbHelper().getBgreadingsDataFromTime(fromTime, true);
|
|
||||||
bgReadingsArray = iobCobCalculatorPlugin.getBgReadings();
|
|
||||||
List<DataPointWithLabelInterface> bgListArray = new ArrayList<>();
|
|
||||||
|
|
||||||
if (bgReadingsArray == null || bgReadingsArray.size() == 0) {
|
|
||||||
aapsLogger.debug(LTag.OVERVIEW, "No BG data.");
|
|
||||||
maxY = 10;
|
|
||||||
minY = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (BgReading bg : bgReadingsArray) {
|
|
||||||
if (bg.date < fromTime || bg.date > toTime) continue;
|
|
||||||
if (bg.value > maxBgValue) maxBgValue = bg.value;
|
|
||||||
bgListArray.add(bg);
|
|
||||||
}
|
|
||||||
if (predictions != null) {
|
|
||||||
Collections.sort(predictions, (o1, o2) -> Double.compare(o1.getX(), o2.getX()));
|
|
||||||
for (BgReading prediction : predictions) {
|
|
||||||
if (prediction.value >= 40)
|
|
||||||
bgListArray.add(prediction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
maxBgValue = Profile.fromMgdlToUnits(maxBgValue, units);
|
|
||||||
maxBgValue = units.equals(Constants.MGDL) ? Round.roundTo(maxBgValue, 40d) + 80 : Round.roundTo(maxBgValue, 2d) + 4;
|
|
||||||
if (highLine > maxBgValue) maxBgValue = highLine;
|
|
||||||
int numOfVertLines = units.equals(Constants.MGDL) ? (int) (maxBgValue / 40 + 1) : (int) (maxBgValue / 2 + 1);
|
|
||||||
|
|
||||||
DataPointWithLabelInterface[] bg = new DataPointWithLabelInterface[bgListArray.size()];
|
|
||||||
bg = bgListArray.toArray(bg);
|
|
||||||
|
|
||||||
|
|
||||||
maxY = maxBgValue;
|
|
||||||
minY = 0;
|
|
||||||
// set manual y bounds to have nice steps
|
|
||||||
graph.getGridLabelRenderer().setNumVerticalLabels(numOfVertLines);
|
|
||||||
|
|
||||||
addSeries(new PointsWithLabelGraphSeries<>(bg));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addInRangeArea(long fromTime, long toTime, double lowLine, double highLine) {
|
|
||||||
AreaGraphSeries<DoubleDataPoint> inRangeAreaSeries;
|
|
||||||
|
|
||||||
DoubleDataPoint[] inRangeAreaDataPoints = new DoubleDataPoint[]{
|
|
||||||
new DoubleDataPoint(fromTime, lowLine, highLine),
|
|
||||||
new DoubleDataPoint(toTime, lowLine, highLine)
|
|
||||||
};
|
|
||||||
inRangeAreaSeries = new AreaGraphSeries<>(inRangeAreaDataPoints);
|
|
||||||
inRangeAreaSeries.setColor(0);
|
|
||||||
inRangeAreaSeries.setDrawBackground(true);
|
|
||||||
inRangeAreaSeries.setBackgroundColor(resourceHelper.gc(R.color.inrangebackground));
|
|
||||||
|
|
||||||
addSeries(inRangeAreaSeries);
|
|
||||||
}
|
|
||||||
|
|
||||||
// scale in % of vertical size (like 0.3)
|
|
||||||
public void addBasals(long fromTime, long toTime, double scale) {
|
|
||||||
LineGraphSeries<ScaledDataPoint> basalsLineSeries;
|
|
||||||
LineGraphSeries<ScaledDataPoint> absoluteBasalsLineSeries;
|
|
||||||
LineGraphSeries<ScaledDataPoint> baseBasalsSeries;
|
|
||||||
LineGraphSeries<ScaledDataPoint> tempBasalsSeries;
|
|
||||||
|
|
||||||
double maxBasalValueFound = 0d;
|
|
||||||
Scale basalScale = new Scale();
|
|
||||||
|
|
||||||
List<ScaledDataPoint> baseBasalArray = new ArrayList<>();
|
|
||||||
List<ScaledDataPoint> tempBasalArray = new ArrayList<>();
|
|
||||||
List<ScaledDataPoint> basalLineArray = new ArrayList<>();
|
|
||||||
List<ScaledDataPoint> absoluteBasalLineArray = new ArrayList<>();
|
|
||||||
double lastLineBasal = 0;
|
|
||||||
double lastAbsoluteLineBasal = -1;
|
|
||||||
double lastBaseBasal = 0;
|
|
||||||
double lastTempBasal = 0;
|
|
||||||
for (long time = fromTime; time < toTime; time += 60 * 1000L) {
|
|
||||||
Profile profile = profileFunction.getProfile(time);
|
|
||||||
if (profile == null) continue;
|
|
||||||
BasalData basalData = iobCobCalculatorPlugin.getBasalData(profile, time);
|
|
||||||
double baseBasalValue = basalData.basal;
|
|
||||||
double absoluteLineValue = baseBasalValue;
|
|
||||||
double tempBasalValue = 0;
|
|
||||||
double basal = 0d;
|
|
||||||
if (basalData.isTempBasalRunning) {
|
|
||||||
absoluteLineValue = tempBasalValue = basalData.tempBasalAbsolute;
|
|
||||||
if (tempBasalValue != lastTempBasal) {
|
|
||||||
tempBasalArray.add(new ScaledDataPoint(time, lastTempBasal, basalScale));
|
|
||||||
tempBasalArray.add(new ScaledDataPoint(time, basal = tempBasalValue, basalScale));
|
|
||||||
}
|
|
||||||
if (lastBaseBasal != 0d) {
|
|
||||||
baseBasalArray.add(new ScaledDataPoint(time, lastBaseBasal, basalScale));
|
|
||||||
baseBasalArray.add(new ScaledDataPoint(time, 0d, basalScale));
|
|
||||||
lastBaseBasal = 0d;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (baseBasalValue != lastBaseBasal) {
|
|
||||||
baseBasalArray.add(new ScaledDataPoint(time, lastBaseBasal, basalScale));
|
|
||||||
baseBasalArray.add(new ScaledDataPoint(time, basal = baseBasalValue, basalScale));
|
|
||||||
lastBaseBasal = baseBasalValue;
|
|
||||||
}
|
|
||||||
if (lastTempBasal != 0) {
|
|
||||||
tempBasalArray.add(new ScaledDataPoint(time, lastTempBasal, basalScale));
|
|
||||||
tempBasalArray.add(new ScaledDataPoint(time, 0d, basalScale));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (baseBasalValue != lastLineBasal) {
|
|
||||||
basalLineArray.add(new ScaledDataPoint(time, lastLineBasal, basalScale));
|
|
||||||
basalLineArray.add(new ScaledDataPoint(time, baseBasalValue, basalScale));
|
|
||||||
}
|
|
||||||
if (absoluteLineValue != lastAbsoluteLineBasal) {
|
|
||||||
absoluteBasalLineArray.add(new ScaledDataPoint(time, lastAbsoluteLineBasal, basalScale));
|
|
||||||
absoluteBasalLineArray.add(new ScaledDataPoint(time, basal, basalScale));
|
|
||||||
}
|
|
||||||
|
|
||||||
lastAbsoluteLineBasal = absoluteLineValue;
|
|
||||||
lastLineBasal = baseBasalValue;
|
|
||||||
lastTempBasal = tempBasalValue;
|
|
||||||
maxBasalValueFound = Math.max(maxBasalValueFound, Math.max(tempBasalValue, baseBasalValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
basalLineArray.add(new ScaledDataPoint(toTime, lastLineBasal, basalScale));
|
|
||||||
baseBasalArray.add(new ScaledDataPoint(toTime, lastBaseBasal, basalScale));
|
|
||||||
tempBasalArray.add(new ScaledDataPoint(toTime, lastTempBasal, basalScale));
|
|
||||||
absoluteBasalLineArray.add(new ScaledDataPoint(toTime, lastAbsoluteLineBasal, basalScale));
|
|
||||||
|
|
||||||
ScaledDataPoint[] baseBasal = new ScaledDataPoint[baseBasalArray.size()];
|
|
||||||
baseBasal = baseBasalArray.toArray(baseBasal);
|
|
||||||
baseBasalsSeries = new LineGraphSeries<>(baseBasal);
|
|
||||||
baseBasalsSeries.setDrawBackground(true);
|
|
||||||
baseBasalsSeries.setBackgroundColor(resourceHelper.gc(R.color.basebasal));
|
|
||||||
baseBasalsSeries.setThickness(0);
|
|
||||||
|
|
||||||
ScaledDataPoint[] tempBasal = new ScaledDataPoint[tempBasalArray.size()];
|
|
||||||
tempBasal = tempBasalArray.toArray(tempBasal);
|
|
||||||
tempBasalsSeries = new LineGraphSeries<>(tempBasal);
|
|
||||||
tempBasalsSeries.setDrawBackground(true);
|
|
||||||
tempBasalsSeries.setBackgroundColor(resourceHelper.gc(R.color.tempbasal));
|
|
||||||
tempBasalsSeries.setThickness(0);
|
|
||||||
|
|
||||||
ScaledDataPoint[] basalLine = new ScaledDataPoint[basalLineArray.size()];
|
|
||||||
basalLine = basalLineArray.toArray(basalLine);
|
|
||||||
basalsLineSeries = new LineGraphSeries<>(basalLine);
|
|
||||||
Paint paint = new Paint();
|
|
||||||
paint.setStyle(Paint.Style.STROKE);
|
|
||||||
paint.setStrokeWidth(resourceHelper.getDisplayMetrics().scaledDensity * 2);
|
|
||||||
paint.setPathEffect(new DashPathEffect(new float[]{2, 4}, 0));
|
|
||||||
paint.setColor(resourceHelper.gc(R.color.basal));
|
|
||||||
basalsLineSeries.setCustomPaint(paint);
|
|
||||||
|
|
||||||
ScaledDataPoint[] absoluteBasalLine = new ScaledDataPoint[absoluteBasalLineArray.size()];
|
|
||||||
absoluteBasalLine = absoluteBasalLineArray.toArray(absoluteBasalLine);
|
|
||||||
absoluteBasalsLineSeries = new LineGraphSeries<>(absoluteBasalLine);
|
|
||||||
Paint absolutePaint = new Paint();
|
|
||||||
absolutePaint.setStyle(Paint.Style.STROKE);
|
|
||||||
absolutePaint.setStrokeWidth(resourceHelper.getDisplayMetrics().scaledDensity * 2);
|
|
||||||
absolutePaint.setColor(resourceHelper.gc(R.color.basal));
|
|
||||||
absoluteBasalsLineSeries.setCustomPaint(absolutePaint);
|
|
||||||
|
|
||||||
basalScale.setMultiplier(maxY * scale / maxBasalValueFound);
|
|
||||||
|
|
||||||
addSeries(baseBasalsSeries);
|
|
||||||
addSeries(tempBasalsSeries);
|
|
||||||
addSeries(basalsLineSeries);
|
|
||||||
addSeries(absoluteBasalsLineSeries);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addTargetLine(long fromTime, long toTime, Profile profile, LoopPlugin.LastRun lastRun) {
|
|
||||||
LineGraphSeries<DataPoint> targetsSeries;
|
|
||||||
|
|
||||||
Scale targetsScale = new Scale();
|
|
||||||
targetsScale.setMultiplier(1);
|
|
||||||
|
|
||||||
List<DataPoint> targetsSeriesArray = new ArrayList<>();
|
|
||||||
double lastTarget = -1;
|
|
||||||
|
|
||||||
if (lastRun != null && lastRun.constraintsProcessed != null) {
|
|
||||||
APSResult apsResult = lastRun.constraintsProcessed;
|
|
||||||
long latestPredictionsTime = apsResult.getLatestPredictionsTime();
|
|
||||||
if (latestPredictionsTime > toTime) {
|
|
||||||
toTime = latestPredictionsTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (long time = fromTime; time < toTime; time += 5 * 60 * 1000L) {
|
|
||||||
TempTarget tt = treatmentsPlugin.getTempTargetFromHistory(time);
|
|
||||||
double value;
|
|
||||||
if (tt == null) {
|
|
||||||
value = Profile.fromMgdlToUnits((profile.getTargetLowMgdl(time) + profile.getTargetHighMgdl(time)) / 2, profileFunction.getUnits());
|
|
||||||
} else {
|
|
||||||
value = Profile.fromMgdlToUnits(tt.target(), profileFunction.getUnits());
|
|
||||||
}
|
|
||||||
if (lastTarget != value) {
|
|
||||||
if (lastTarget != -1)
|
|
||||||
targetsSeriesArray.add(new DataPoint(time, lastTarget));
|
|
||||||
targetsSeriesArray.add(new DataPoint(time, value));
|
|
||||||
}
|
|
||||||
lastTarget = value;
|
|
||||||
}
|
|
||||||
targetsSeriesArray.add(new DataPoint(toTime, lastTarget));
|
|
||||||
|
|
||||||
DataPoint[] targets = new DataPoint[targetsSeriesArray.size()];
|
|
||||||
targets = targetsSeriesArray.toArray(targets);
|
|
||||||
targetsSeries = new LineGraphSeries<>(targets);
|
|
||||||
targetsSeries.setDrawBackground(false);
|
|
||||||
targetsSeries.setColor(resourceHelper.gc(R.color.tempTargetBackground));
|
|
||||||
targetsSeries.setThickness(2);
|
|
||||||
|
|
||||||
addSeries(targetsSeries);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addTreatments(long fromTime, long endTime) {
|
|
||||||
List<DataPointWithLabelInterface> filteredTreatments = new ArrayList<>();
|
|
||||||
|
|
||||||
List<Treatment> treatments = treatmentsPlugin.getTreatmentsFromHistory();
|
|
||||||
|
|
||||||
for (int tx = 0; tx < treatments.size(); tx++) {
|
|
||||||
Treatment t = treatments.get(tx);
|
|
||||||
if (t.getX() < fromTime || t.getX() > endTime) continue;
|
|
||||||
if (t.isSMB && !t.isValid) continue;
|
|
||||||
t.setY(getNearestBg((long) t.getX()));
|
|
||||||
filteredTreatments.add(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProfileSwitch
|
|
||||||
List<ProfileSwitch> profileSwitches = treatmentsPlugin.getProfileSwitchesFromHistory().getList();
|
|
||||||
|
|
||||||
for (int tx = 0; tx < profileSwitches.size(); tx++) {
|
|
||||||
DataPointWithLabelInterface t = profileSwitches.get(tx);
|
|
||||||
if (t.getX() < fromTime || t.getX() > endTime) continue;
|
|
||||||
filteredTreatments.add(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extended bolus
|
|
||||||
if (!activePlugin.getActivePump().isFakingTempsByExtendedBoluses()) {
|
|
||||||
List<ExtendedBolus> extendedBoluses = treatmentsPlugin.getExtendedBolusesFromHistory().getList();
|
|
||||||
|
|
||||||
for (int tx = 0; tx < extendedBoluses.size(); tx++) {
|
|
||||||
DataPointWithLabelInterface t = extendedBoluses.get(tx);
|
|
||||||
if (t.getX() + t.getDuration() < fromTime || t.getX() > endTime) continue;
|
|
||||||
if (t.getDuration() == 0) continue;
|
|
||||||
t.setY(getNearestBg((long) t.getX()));
|
|
||||||
filteredTreatments.add(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Careportal
|
|
||||||
List<CareportalEvent> careportalEvents = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime - 6 * 60 * 60 * 1000, true);
|
|
||||||
|
|
||||||
for (int tx = 0; tx < careportalEvents.size(); tx++) {
|
|
||||||
DataPointWithLabelInterface t = careportalEvents.get(tx);
|
|
||||||
if (t.getX() + t.getDuration() < fromTime || t.getX() > endTime) continue;
|
|
||||||
t.setY(getNearestBg((long) t.getX()));
|
|
||||||
filteredTreatments.add(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
DataPointWithLabelInterface[] treatmentsArray = new DataPointWithLabelInterface[filteredTreatments.size()];
|
|
||||||
treatmentsArray = filteredTreatments.toArray(treatmentsArray);
|
|
||||||
addSeries(new PointsWithLabelGraphSeries<>(treatmentsArray));
|
|
||||||
}
|
|
||||||
|
|
||||||
private double getNearestBg(long date) {
|
|
||||||
if (bgReadingsArray == null)
|
|
||||||
return Profile.fromMgdlToUnits(100, units);
|
|
||||||
for (int r = 0; r < bgReadingsArray.size(); r++) {
|
|
||||||
BgReading reading = bgReadingsArray.get(r);
|
|
||||||
if (reading.date > date) continue;
|
|
||||||
return Profile.fromMgdlToUnits(reading.value, units);
|
|
||||||
}
|
|
||||||
return bgReadingsArray.size() > 0
|
|
||||||
? Profile.fromMgdlToUnits(bgReadingsArray.get(0).value, units) : Profile.fromMgdlToUnits(100, units);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addActivity(long fromTime, long toTime, boolean useForScale, double scale) {
|
|
||||||
FixedLineGraphSeries<ScaledDataPoint> actSeriesHist;
|
|
||||||
List<ScaledDataPoint> actArrayHist = new ArrayList<>();
|
|
||||||
FixedLineGraphSeries<ScaledDataPoint> actSeriesPred;
|
|
||||||
List<ScaledDataPoint> actArrayPred = new ArrayList<>();
|
|
||||||
|
|
||||||
double now = System.currentTimeMillis();
|
|
||||||
Scale actScale = new Scale();
|
|
||||||
IobTotal total;
|
|
||||||
double maxIAValue = 0;
|
|
||||||
|
|
||||||
for (long time = fromTime; time <= toTime; time += 5 * 60 * 1000L) {
|
|
||||||
Profile profile = profileFunction.getProfile(time);
|
|
||||||
double act;
|
|
||||||
if (profile == null) continue;
|
|
||||||
total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile);
|
|
||||||
act = total.activity;
|
|
||||||
|
|
||||||
if (time <= now)
|
|
||||||
actArrayHist.add(new ScaledDataPoint(time, act, actScale));
|
|
||||||
else
|
|
||||||
actArrayPred.add(new ScaledDataPoint(time, act, actScale));
|
|
||||||
|
|
||||||
maxIAValue = Math.max(maxIAValue, Math.abs(act));
|
|
||||||
}
|
|
||||||
|
|
||||||
ScaledDataPoint[] actData = new ScaledDataPoint[actArrayHist.size()];
|
|
||||||
actData = actArrayHist.toArray(actData);
|
|
||||||
actSeriesHist = new FixedLineGraphSeries<>(actData);
|
|
||||||
actSeriesHist.setDrawBackground(false);
|
|
||||||
actSeriesHist.setColor(resourceHelper.gc(R.color.activity));
|
|
||||||
actSeriesHist.setThickness(3);
|
|
||||||
|
|
||||||
addSeries(actSeriesHist);
|
|
||||||
|
|
||||||
actData = new ScaledDataPoint[actArrayPred.size()];
|
|
||||||
actData = actArrayPred.toArray(actData);
|
|
||||||
actSeriesPred = new FixedLineGraphSeries<>(actData);
|
|
||||||
|
|
||||||
Paint paint = new Paint();
|
|
||||||
paint.setStyle(Paint.Style.STROKE);
|
|
||||||
paint.setStrokeWidth(3);
|
|
||||||
paint.setPathEffect(new DashPathEffect(new float[]{4, 4}, 0));
|
|
||||||
paint.setColor(resourceHelper.gc(R.color.activity));
|
|
||||||
actSeriesPred.setCustomPaint(paint);
|
|
||||||
|
|
||||||
if (useForScale) {
|
|
||||||
maxY = maxIAValue;
|
|
||||||
minY = -maxIAValue;
|
|
||||||
}
|
|
||||||
actScale.setMultiplier(maxY * scale / maxIAValue);
|
|
||||||
|
|
||||||
addSeries(actSeriesPred);
|
|
||||||
}
|
|
||||||
|
|
||||||
// scale in % of vertical size (like 0.3)
|
|
||||||
public void addIob(long fromTime, long toTime, boolean useForScale, double scale, boolean showPrediction) {
|
|
||||||
FixedLineGraphSeries<ScaledDataPoint> iobSeries;
|
|
||||||
List<ScaledDataPoint> iobArray = new ArrayList<>();
|
|
||||||
Double maxIobValueFound = Double.MIN_VALUE;
|
|
||||||
double lastIob = 0;
|
|
||||||
Scale iobScale = new Scale();
|
|
||||||
|
|
||||||
for (long time = fromTime; time <= toTime; time += 5 * 60 * 1000L) {
|
|
||||||
Profile profile = profileFunction.getProfile(time);
|
|
||||||
double iob = 0d;
|
|
||||||
if (profile != null)
|
|
||||||
iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile).iob;
|
|
||||||
if (Math.abs(lastIob - iob) > 0.02) {
|
|
||||||
if (Math.abs(lastIob - iob) > 0.2)
|
|
||||||
iobArray.add(new ScaledDataPoint(time, lastIob, iobScale));
|
|
||||||
iobArray.add(new ScaledDataPoint(time, iob, iobScale));
|
|
||||||
maxIobValueFound = Math.max(maxIobValueFound, Math.abs(iob));
|
|
||||||
lastIob = iob;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ScaledDataPoint[] iobData = new ScaledDataPoint[iobArray.size()];
|
|
||||||
iobData = iobArray.toArray(iobData);
|
|
||||||
iobSeries = new FixedLineGraphSeries<>(iobData);
|
|
||||||
iobSeries.setDrawBackground(true);
|
|
||||||
iobSeries.setBackgroundColor(0x80FFFFFF & resourceHelper.gc(R.color.iob)); //50%
|
|
||||||
iobSeries.setColor(resourceHelper.gc(R.color.iob));
|
|
||||||
iobSeries.setThickness(3);
|
|
||||||
|
|
||||||
if (showPrediction) {
|
|
||||||
AutosensResult lastAutosensResult;
|
|
||||||
AutosensData autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("GraphData");
|
|
||||||
if (autosensData == null)
|
|
||||||
lastAutosensResult = new AutosensResult();
|
|
||||||
else
|
|
||||||
lastAutosensResult = autosensData.autosensResult;
|
|
||||||
boolean isTempTarget = treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis()) != null;
|
|
||||||
|
|
||||||
List<DataPointWithLabelInterface> iobPred = new ArrayList<>();
|
|
||||||
IobTotal[] iobPredArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget);
|
|
||||||
for (IobTotal i : iobPredArray) {
|
|
||||||
iobPred.add(i.setColor(resourceHelper.gc(R.color.iobPredAS)));
|
|
||||||
maxIobValueFound = Math.max(maxIobValueFound, Math.abs(i.iob));
|
|
||||||
}
|
|
||||||
DataPointWithLabelInterface[] iobp = new DataPointWithLabelInterface[iobPred.size()];
|
|
||||||
iobp = iobPred.toArray(iobp);
|
|
||||||
addSeries(new PointsWithLabelGraphSeries<>(iobp));
|
|
||||||
|
|
||||||
|
|
||||||
List<DataPointWithLabelInterface> iobPred2 = new ArrayList<>();
|
|
||||||
IobTotal[] iobPredArray2 = iobCobCalculatorPlugin.calculateIobArrayForSMB(new AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget);
|
|
||||||
for (IobTotal i : iobPredArray2) {
|
|
||||||
iobPred2.add(i.setColor(resourceHelper.gc(R.color.iobPred)));
|
|
||||||
maxIobValueFound = Math.max(maxIobValueFound, Math.abs(i.iob));
|
|
||||||
}
|
|
||||||
DataPointWithLabelInterface[] iobp2 = new DataPointWithLabelInterface[iobPred2.size()];
|
|
||||||
iobp2 = iobPred2.toArray(iobp2);
|
|
||||||
addSeries(new PointsWithLabelGraphSeries<>(iobp2));
|
|
||||||
|
|
||||||
aapsLogger.debug(LTag.AUTOSENS, "IOB pred for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredArray));
|
|
||||||
aapsLogger.debug(LTag.AUTOSENS, "IOB pred for AS=" + DecimalFormatter.to2Decimal(1) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredArray2));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useForScale) {
|
|
||||||
maxY = maxIobValueFound;
|
|
||||||
minY = -maxIobValueFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
iobScale.setMultiplier(maxY * scale / maxIobValueFound);
|
|
||||||
|
|
||||||
addSeries(iobSeries);
|
|
||||||
}
|
|
||||||
|
|
||||||
// scale in % of vertical size (like 0.3)
|
|
||||||
public void addCob(long fromTime, long toTime, boolean useForScale, double scale) {
|
|
||||||
List<DataPointWithLabelInterface> minFailoverActiveList = new ArrayList<>();
|
|
||||||
FixedLineGraphSeries<ScaledDataPoint> cobSeries;
|
|
||||||
List<ScaledDataPoint> cobArray = new ArrayList<>();
|
|
||||||
Double maxCobValueFound = 0d;
|
|
||||||
int lastCob = 0;
|
|
||||||
Scale cobScale = new Scale();
|
|
||||||
|
|
||||||
for (long time = fromTime; time <= toTime; time += 5 * 60 * 1000L) {
|
|
||||||
AutosensData autosensData = iobCobCalculatorPlugin.getAutosensData(time);
|
|
||||||
if (autosensData != null) {
|
|
||||||
int cob = (int) autosensData.cob;
|
|
||||||
if (cob != lastCob) {
|
|
||||||
if (autosensData.carbsFromBolus > 0)
|
|
||||||
cobArray.add(new ScaledDataPoint(time, lastCob, cobScale));
|
|
||||||
cobArray.add(new ScaledDataPoint(time, cob, cobScale));
|
|
||||||
maxCobValueFound = Math.max(maxCobValueFound, cob);
|
|
||||||
lastCob = cob;
|
|
||||||
}
|
|
||||||
if (autosensData.failoverToMinAbsorbtionRate) {
|
|
||||||
autosensData.setScale(cobScale);
|
|
||||||
autosensData.setChartTime(time);
|
|
||||||
minFailoverActiveList.add(autosensData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// COB
|
|
||||||
ScaledDataPoint[] cobData = new ScaledDataPoint[cobArray.size()];
|
|
||||||
cobData = cobArray.toArray(cobData);
|
|
||||||
cobSeries = new FixedLineGraphSeries<>(cobData);
|
|
||||||
cobSeries.setDrawBackground(true);
|
|
||||||
cobSeries.setBackgroundColor(0x80FFFFFF & resourceHelper.gc(R.color.cob)); //50%
|
|
||||||
cobSeries.setColor(resourceHelper.gc(R.color.cob));
|
|
||||||
cobSeries.setThickness(3);
|
|
||||||
|
|
||||||
if (useForScale) {
|
|
||||||
maxY = maxCobValueFound;
|
|
||||||
minY = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cobScale.setMultiplier(maxY * scale / maxCobValueFound);
|
|
||||||
|
|
||||||
addSeries(cobSeries);
|
|
||||||
|
|
||||||
DataPointWithLabelInterface[] minFailover = new DataPointWithLabelInterface[minFailoverActiveList.size()];
|
|
||||||
minFailover = minFailoverActiveList.toArray(minFailover);
|
|
||||||
addSeries(new PointsWithLabelGraphSeries<>(minFailover));
|
|
||||||
}
|
|
||||||
|
|
||||||
// scale in % of vertical size (like 0.3)
|
|
||||||
public void addDeviations(long fromTime, long toTime, boolean useForScale, double scale) {
|
|
||||||
class DeviationDataPoint extends ScaledDataPoint {
|
|
||||||
public int color;
|
|
||||||
|
|
||||||
private DeviationDataPoint(double x, double y, int color, Scale scale) {
|
|
||||||
super(x, y, scale);
|
|
||||||
this.color = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BarGraphSeries<DeviationDataPoint> devSeries;
|
|
||||||
List<DeviationDataPoint> devArray = new ArrayList<>();
|
|
||||||
Double maxDevValueFound = 0d;
|
|
||||||
Scale devScale = new Scale();
|
|
||||||
|
|
||||||
for (long time = fromTime; time <= toTime; time += 5 * 60 * 1000L) {
|
|
||||||
AutosensData autosensData = iobCobCalculatorPlugin.getAutosensData(time);
|
|
||||||
if (autosensData != null) {
|
|
||||||
int color = resourceHelper.gc(R.color.deviationblack); // "="
|
|
||||||
if (autosensData.type.equals("") || autosensData.type.equals("non-meal")) {
|
|
||||||
if (autosensData.pastSensitivity.equals("C"))
|
|
||||||
color = resourceHelper.gc(R.color.deviationgrey);
|
|
||||||
if (autosensData.pastSensitivity.equals("+"))
|
|
||||||
color = resourceHelper.gc(R.color.deviationgreen);
|
|
||||||
if (autosensData.pastSensitivity.equals("-"))
|
|
||||||
color = resourceHelper.gc(R.color.deviationred);
|
|
||||||
} else if (autosensData.type.equals("uam")) {
|
|
||||||
color = resourceHelper.gc(R.color.uam);
|
|
||||||
} else if (autosensData.type.equals("csf")) {
|
|
||||||
color = resourceHelper.gc(R.color.deviationgrey);
|
|
||||||
}
|
|
||||||
devArray.add(new DeviationDataPoint(time, autosensData.deviation, color, devScale));
|
|
||||||
maxDevValueFound = Math.max(maxDevValueFound, Math.abs(autosensData.deviation));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEVIATIONS
|
|
||||||
DeviationDataPoint[] devData = new DeviationDataPoint[devArray.size()];
|
|
||||||
devData = devArray.toArray(devData);
|
|
||||||
devSeries = new BarGraphSeries<>(devData);
|
|
||||||
devSeries.setValueDependentColor(data -> data.color);
|
|
||||||
|
|
||||||
if (useForScale) {
|
|
||||||
maxY = maxDevValueFound;
|
|
||||||
minY = -maxY;
|
|
||||||
}
|
|
||||||
|
|
||||||
devScale.setMultiplier(maxY * scale / maxDevValueFound);
|
|
||||||
|
|
||||||
addSeries(devSeries);
|
|
||||||
}
|
|
||||||
|
|
||||||
// scale in % of vertical size (like 0.3)
|
|
||||||
public void addRatio(long fromTime, long toTime, boolean useForScale, double scale) {
|
|
||||||
LineGraphSeries<ScaledDataPoint> ratioSeries;
|
|
||||||
List<ScaledDataPoint> ratioArray = new ArrayList<>();
|
|
||||||
double maxRatioValueFound = Double.MIN_VALUE;
|
|
||||||
double minRatioValueFound = Double.MAX_VALUE;
|
|
||||||
Scale ratioScale = new Scale();
|
|
||||||
|
|
||||||
for (long time = fromTime; time <= toTime; time += 5 * 60 * 1000L) {
|
|
||||||
AutosensData autosensData = iobCobCalculatorPlugin.getAutosensData(time);
|
|
||||||
if (autosensData != null) {
|
|
||||||
ratioArray.add(new ScaledDataPoint(time, autosensData.autosensResult.ratio - 1, ratioScale));
|
|
||||||
maxRatioValueFound = Math.max(maxRatioValueFound, autosensData.autosensResult.ratio - 1);
|
|
||||||
minRatioValueFound = Math.min(minRatioValueFound, autosensData.autosensResult.ratio - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RATIOS
|
|
||||||
ScaledDataPoint[] ratioData = new ScaledDataPoint[ratioArray.size()];
|
|
||||||
ratioData = ratioArray.toArray(ratioData);
|
|
||||||
ratioSeries = new LineGraphSeries<>(ratioData);
|
|
||||||
ratioSeries.setColor(resourceHelper.gc(R.color.ratio));
|
|
||||||
ratioSeries.setThickness(3);
|
|
||||||
|
|
||||||
if (useForScale) {
|
|
||||||
maxY = Math.max(maxRatioValueFound, Math.abs(minRatioValueFound));
|
|
||||||
minY = -maxY;
|
|
||||||
}
|
|
||||||
|
|
||||||
ratioScale.setMultiplier(maxY * scale / Math.max(maxRatioValueFound, Math.abs(minRatioValueFound)));
|
|
||||||
|
|
||||||
addSeries(ratioSeries);
|
|
||||||
}
|
|
||||||
|
|
||||||
// scale in % of vertical size (like 0.3)
|
|
||||||
public void addDeviationSlope(long fromTime, long toTime, boolean useForScale, double scale) {
|
|
||||||
LineGraphSeries<ScaledDataPoint> dsMaxSeries;
|
|
||||||
LineGraphSeries<ScaledDataPoint> dsMinSeries;
|
|
||||||
List<ScaledDataPoint> dsMaxArray = new ArrayList<>();
|
|
||||||
List<ScaledDataPoint> dsMinArray = new ArrayList<>();
|
|
||||||
double maxFromMaxValueFound = 0d;
|
|
||||||
double maxFromMinValueFound = 0d;
|
|
||||||
Scale dsMaxScale = new Scale();
|
|
||||||
Scale dsMinScale = new Scale();
|
|
||||||
|
|
||||||
for (long time = fromTime; time <= toTime; time += 5 * 60 * 1000L) {
|
|
||||||
AutosensData autosensData = iobCobCalculatorPlugin.getAutosensData(time);
|
|
||||||
if (autosensData != null) {
|
|
||||||
dsMaxArray.add(new ScaledDataPoint(time, autosensData.slopeFromMaxDeviation, dsMaxScale));
|
|
||||||
dsMinArray.add(new ScaledDataPoint(time, autosensData.slopeFromMinDeviation, dsMinScale));
|
|
||||||
maxFromMaxValueFound = Math.max(maxFromMaxValueFound, Math.abs(autosensData.slopeFromMaxDeviation));
|
|
||||||
maxFromMinValueFound = Math.max(maxFromMinValueFound, Math.abs(autosensData.slopeFromMinDeviation));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slopes
|
|
||||||
ScaledDataPoint[] ratioMaxData = new ScaledDataPoint[dsMaxArray.size()];
|
|
||||||
ratioMaxData = dsMaxArray.toArray(ratioMaxData);
|
|
||||||
dsMaxSeries = new LineGraphSeries<>(ratioMaxData);
|
|
||||||
dsMaxSeries.setColor(resourceHelper.gc(R.color.devslopepos));
|
|
||||||
dsMaxSeries.setThickness(3);
|
|
||||||
|
|
||||||
ScaledDataPoint[] ratioMinData = new ScaledDataPoint[dsMinArray.size()];
|
|
||||||
ratioMinData = dsMinArray.toArray(ratioMinData);
|
|
||||||
dsMinSeries = new LineGraphSeries<>(ratioMinData);
|
|
||||||
dsMinSeries.setColor(resourceHelper.gc(R.color.devslopeneg));
|
|
||||||
dsMinSeries.setThickness(3);
|
|
||||||
|
|
||||||
if (useForScale) {
|
|
||||||
maxY = Math.max(maxFromMaxValueFound, maxFromMinValueFound);
|
|
||||||
minY = -maxY;
|
|
||||||
}
|
|
||||||
|
|
||||||
dsMaxScale.setMultiplier(maxY * scale / maxFromMaxValueFound);
|
|
||||||
dsMinScale.setMultiplier(maxY * scale / maxFromMinValueFound);
|
|
||||||
|
|
||||||
addSeries(dsMaxSeries);
|
|
||||||
addSeries(dsMinSeries);
|
|
||||||
}
|
|
||||||
|
|
||||||
// scale in % of vertical size (like 0.3)
|
|
||||||
public void addNowLine(long now) {
|
|
||||||
LineGraphSeries<DataPoint> seriesNow;
|
|
||||||
DataPoint[] nowPoints = new DataPoint[]{
|
|
||||||
new DataPoint(now, 0),
|
|
||||||
new DataPoint(now, maxY)
|
|
||||||
};
|
|
||||||
|
|
||||||
seriesNow = new LineGraphSeries<>(nowPoints);
|
|
||||||
seriesNow.setDrawDataPoints(false);
|
|
||||||
// custom paint to make a dotted line
|
|
||||||
Paint paint = new Paint();
|
|
||||||
paint.setStyle(Paint.Style.STROKE);
|
|
||||||
paint.setStrokeWidth(2);
|
|
||||||
paint.setPathEffect(new DashPathEffect(new float[]{10, 20}, 0));
|
|
||||||
paint.setColor(Color.WHITE);
|
|
||||||
seriesNow.setCustomPaint(paint);
|
|
||||||
|
|
||||||
addSeries(seriesNow);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void formatAxis(long fromTime, long endTime) {
|
|
||||||
graph.getViewport().setMaxX(endTime);
|
|
||||||
graph.getViewport().setMinX(fromTime);
|
|
||||||
graph.getViewport().setXAxisBoundsManual(true);
|
|
||||||
graph.getGridLabelRenderer().setLabelFormatter(new TimeAsXAxisLabelFormatter("HH"));
|
|
||||||
graph.getGridLabelRenderer().setNumHorizontalLabels(7); // only 7 because of the space
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addSeries(Series s) {
|
|
||||||
series.add(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void performUpdate() {
|
|
||||||
// clear old data
|
|
||||||
graph.getSeries().clear();
|
|
||||||
|
|
||||||
// add precalculated series
|
|
||||||
for (Series s : series) {
|
|
||||||
if (!s.isEmpty()) {
|
|
||||||
s.onGraphViewAttached(graph);
|
|
||||||
graph.getSeries().add(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double step = 1d;
|
|
||||||
if (maxY < 1) step = 0.1d;
|
|
||||||
graph.getViewport().setMaxY(Round.ceilTo(maxY, step));
|
|
||||||
graph.getViewport().setMinY(Round.floorTo(minY, step));
|
|
||||||
graph.getViewport().setYAxisBoundsManual(true);
|
|
||||||
|
|
||||||
// draw it
|
|
||||||
graph.onDataChanged(false, false);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,569 @@
|
||||||
|
package info.nightscout.androidaps.plugins.general.overview.graphData
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.DashPathEffect
|
||||||
|
import android.graphics.Paint
|
||||||
|
import com.jjoe64.graphview.GraphView
|
||||||
|
import com.jjoe64.graphview.series.BarGraphSeries
|
||||||
|
import com.jjoe64.graphview.series.DataPoint
|
||||||
|
import com.jjoe64.graphview.series.LineGraphSeries
|
||||||
|
import com.jjoe64.graphview.series.Series
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.Constants
|
||||||
|
import info.nightscout.androidaps.MainApp
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.data.IobTotal
|
||||||
|
import info.nightscout.androidaps.data.Profile
|
||||||
|
import info.nightscout.androidaps.db.BgReading
|
||||||
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||||
|
import info.nightscout.androidaps.interfaces.TreatmentsInterface
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin.LastRun
|
||||||
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
|
||||||
|
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.*
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult
|
||||||
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
|
||||||
|
import info.nightscout.androidaps.utils.DecimalFormatter
|
||||||
|
import info.nightscout.androidaps.utils.Round
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
class GraphData(injector: HasAndroidInjector, private val graph: GraphView, private val iobCobCalculatorPlugin: IobCobCalculatorPlugin) {
|
||||||
|
|
||||||
|
// IobCobCalculatorPlugin Cannot be injected: HistoryBrowser
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
@Inject lateinit var profileFunction: ProfileFunction
|
||||||
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
|
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||||
|
|
||||||
|
private val treatmentsPlugin: TreatmentsInterface
|
||||||
|
|
||||||
|
var maxY = Double.MIN_VALUE
|
||||||
|
private var minY = Double.MAX_VALUE
|
||||||
|
private var bgReadingsArray: List<BgReading>? = null
|
||||||
|
private val units: String
|
||||||
|
private val series: MutableList<Series<*>> = ArrayList()
|
||||||
|
|
||||||
|
init {
|
||||||
|
injector.androidInjector().inject(this)
|
||||||
|
units = profileFunction.getUnits()
|
||||||
|
treatmentsPlugin = activePlugin.activeTreatments
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNUSED_PARAMETER")
|
||||||
|
fun addBgReadings(fromTime: Long, toTime: Long, lowLine: Double, highLine: Double, predictions: MutableList<BgReading>?) {
|
||||||
|
var maxBgValue = Double.MIN_VALUE
|
||||||
|
bgReadingsArray = iobCobCalculatorPlugin.bgReadings
|
||||||
|
if (bgReadingsArray?.isEmpty() != false) {
|
||||||
|
aapsLogger.debug(LTag.OVERVIEW, "No BG data.")
|
||||||
|
maxY = 10.0
|
||||||
|
minY = 0.0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val bgListArray: MutableList<DataPointWithLabelInterface> = ArrayList()
|
||||||
|
for (bg in bgReadingsArray!!) {
|
||||||
|
if (bg.date < fromTime || bg.date > toTime) continue
|
||||||
|
if (bg.value > maxBgValue) maxBgValue = bg.value
|
||||||
|
bgListArray.add(bg)
|
||||||
|
}
|
||||||
|
if (predictions != null) {
|
||||||
|
predictions.sortWith(Comparator { o1: BgReading, o2: BgReading -> o1.x.compareTo(o2.x) })
|
||||||
|
for (prediction in predictions) if (prediction.value >= 40) bgListArray.add(prediction)
|
||||||
|
}
|
||||||
|
maxBgValue = Profile.fromMgdlToUnits(maxBgValue, units)
|
||||||
|
maxBgValue = if (units == Constants.MGDL) Round.roundTo(maxBgValue, 40.0) + 80 else Round.roundTo(maxBgValue, 2.0) + 4
|
||||||
|
if (highLine > maxBgValue) maxBgValue = highLine
|
||||||
|
val numOfVerticalLines = if (units == Constants.MGDL) (maxBgValue / 40 + 1).toInt() else (maxBgValue / 2 + 1).toInt()
|
||||||
|
maxY = maxBgValue
|
||||||
|
minY = 0.0
|
||||||
|
// set manual y bounds to have nice steps
|
||||||
|
graph.gridLabelRenderer.numVerticalLabels = numOfVerticalLines
|
||||||
|
addSeries(PointsWithLabelGraphSeries(Array(bgListArray.size) { i -> bgListArray[i] }))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addInRangeArea(fromTime: Long, toTime: Long, lowLine: Double, highLine: Double) {
|
||||||
|
val inRangeAreaSeries: AreaGraphSeries<DoubleDataPoint>
|
||||||
|
val inRangeAreaDataPoints = arrayOf(
|
||||||
|
DoubleDataPoint(fromTime.toDouble(), lowLine, highLine),
|
||||||
|
DoubleDataPoint(toTime.toDouble(), lowLine, highLine)
|
||||||
|
)
|
||||||
|
inRangeAreaSeries = AreaGraphSeries(inRangeAreaDataPoints)
|
||||||
|
inRangeAreaSeries.color = 0
|
||||||
|
inRangeAreaSeries.isDrawBackground = true
|
||||||
|
inRangeAreaSeries.backgroundColor = resourceHelper.gc(R.color.inrangebackground)
|
||||||
|
addSeries(inRangeAreaSeries)
|
||||||
|
}
|
||||||
|
|
||||||
|
// scale in % of vertical size (like 0.3)
|
||||||
|
fun addBasals(fromTime: Long, toTime: Long, scale: Double) {
|
||||||
|
var maxBasalValueFound = 0.0
|
||||||
|
val basalScale = Scale()
|
||||||
|
val baseBasalArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||||
|
val tempBasalArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||||
|
val basalLineArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||||
|
val absoluteBasalLineArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||||
|
var lastLineBasal = 0.0
|
||||||
|
var lastAbsoluteLineBasal = -1.0
|
||||||
|
var lastBaseBasal = 0.0
|
||||||
|
var lastTempBasal = 0.0
|
||||||
|
var time = fromTime
|
||||||
|
while (time < toTime) {
|
||||||
|
val profile = profileFunction.getProfile(time)
|
||||||
|
if (profile == null) {
|
||||||
|
time += 60 * 1000L
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
val basalData = iobCobCalculatorPlugin.getBasalData(profile, time)
|
||||||
|
val baseBasalValue = basalData.basal
|
||||||
|
var absoluteLineValue = baseBasalValue
|
||||||
|
var tempBasalValue = 0.0
|
||||||
|
var basal = 0.0
|
||||||
|
if (basalData.isTempBasalRunning) {
|
||||||
|
tempBasalValue = basalData.tempBasalAbsolute
|
||||||
|
absoluteLineValue = tempBasalValue
|
||||||
|
if (tempBasalValue != lastTempBasal) {
|
||||||
|
tempBasalArray.add(ScaledDataPoint(time, lastTempBasal, basalScale))
|
||||||
|
tempBasalArray.add(ScaledDataPoint(time, tempBasalValue.also { basal = it }, basalScale))
|
||||||
|
}
|
||||||
|
if (lastBaseBasal != 0.0) {
|
||||||
|
baseBasalArray.add(ScaledDataPoint(time, lastBaseBasal, basalScale))
|
||||||
|
baseBasalArray.add(ScaledDataPoint(time, 0.0, basalScale))
|
||||||
|
lastBaseBasal = 0.0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (baseBasalValue != lastBaseBasal) {
|
||||||
|
baseBasalArray.add(ScaledDataPoint(time, lastBaseBasal, basalScale))
|
||||||
|
baseBasalArray.add(ScaledDataPoint(time, baseBasalValue.also { basal = it }, basalScale))
|
||||||
|
lastBaseBasal = baseBasalValue
|
||||||
|
}
|
||||||
|
if (lastTempBasal != 0.0) {
|
||||||
|
tempBasalArray.add(ScaledDataPoint(time, lastTempBasal, basalScale))
|
||||||
|
tempBasalArray.add(ScaledDataPoint(time, 0.0, basalScale))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (baseBasalValue != lastLineBasal) {
|
||||||
|
basalLineArray.add(ScaledDataPoint(time, lastLineBasal, basalScale))
|
||||||
|
basalLineArray.add(ScaledDataPoint(time, baseBasalValue, basalScale))
|
||||||
|
}
|
||||||
|
if (absoluteLineValue != lastAbsoluteLineBasal) {
|
||||||
|
absoluteBasalLineArray.add(ScaledDataPoint(time, lastAbsoluteLineBasal, basalScale))
|
||||||
|
absoluteBasalLineArray.add(ScaledDataPoint(time, basal, basalScale))
|
||||||
|
}
|
||||||
|
lastAbsoluteLineBasal = absoluteLineValue
|
||||||
|
lastLineBasal = baseBasalValue
|
||||||
|
lastTempBasal = tempBasalValue
|
||||||
|
maxBasalValueFound = max(maxBasalValueFound, max(tempBasalValue, baseBasalValue))
|
||||||
|
time += 60 * 1000L
|
||||||
|
}
|
||||||
|
|
||||||
|
// final points
|
||||||
|
basalLineArray.add(ScaledDataPoint(toTime, lastLineBasal, basalScale))
|
||||||
|
baseBasalArray.add(ScaledDataPoint(toTime, lastBaseBasal, basalScale))
|
||||||
|
tempBasalArray.add(ScaledDataPoint(toTime, lastTempBasal, basalScale))
|
||||||
|
absoluteBasalLineArray.add(ScaledDataPoint(toTime, lastAbsoluteLineBasal, basalScale))
|
||||||
|
|
||||||
|
// create series
|
||||||
|
addSeries(LineGraphSeries(Array(baseBasalArray.size) { i -> baseBasalArray[i] }).also {
|
||||||
|
it.isDrawBackground = true
|
||||||
|
it.backgroundColor = resourceHelper.gc(R.color.basebasal)
|
||||||
|
it.thickness = 0
|
||||||
|
})
|
||||||
|
addSeries(LineGraphSeries(Array(tempBasalArray.size) { i -> tempBasalArray[i] }).also {
|
||||||
|
it.isDrawBackground = true
|
||||||
|
it.backgroundColor = resourceHelper.gc(R.color.tempbasal)
|
||||||
|
it.thickness = 0
|
||||||
|
})
|
||||||
|
addSeries(LineGraphSeries(Array(basalLineArray.size) { i -> basalLineArray[i] }).also {
|
||||||
|
it.setCustomPaint(Paint().also { paint ->
|
||||||
|
paint.style = Paint.Style.STROKE
|
||||||
|
paint.strokeWidth = resourceHelper.getDisplayMetrics().scaledDensity * 2
|
||||||
|
paint.pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f)
|
||||||
|
paint.color = resourceHelper.gc(R.color.basal)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
addSeries(LineGraphSeries(Array(absoluteBasalLineArray.size) { i -> absoluteBasalLineArray[i] }).also {
|
||||||
|
it.setCustomPaint(Paint().also { absolutePaint ->
|
||||||
|
absolutePaint.style = Paint.Style.STROKE
|
||||||
|
absolutePaint.strokeWidth = resourceHelper.getDisplayMetrics().scaledDensity * 2
|
||||||
|
absolutePaint.color = resourceHelper.gc(R.color.basal)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
basalScale.setMultiplier(maxY * scale / maxBasalValueFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addTargetLine(fromTime: Long, toTimeParam: Long, profile: Profile, lastRun: LastRun?) {
|
||||||
|
var toTime = toTimeParam
|
||||||
|
val targetsSeriesArray: MutableList<DataPoint> = ArrayList()
|
||||||
|
var lastTarget = -1.0
|
||||||
|
lastRun?.constraintsProcessed?.let { toTime = max(it.latestPredictionsTime, toTime) }
|
||||||
|
var time = fromTime
|
||||||
|
while (time < toTime) {
|
||||||
|
val tt = treatmentsPlugin.getTempTargetFromHistory(time)
|
||||||
|
var value: Double
|
||||||
|
value = if (tt == null) {
|
||||||
|
Profile.fromMgdlToUnits((profile.getTargetLowMgdl(time) + profile.getTargetHighMgdl(time)) / 2, units)
|
||||||
|
} else {
|
||||||
|
Profile.fromMgdlToUnits(tt.target(), units)
|
||||||
|
}
|
||||||
|
if (lastTarget != value) {
|
||||||
|
if (lastTarget != -1.0) targetsSeriesArray.add(DataPoint(time.toDouble(), lastTarget))
|
||||||
|
targetsSeriesArray.add(DataPoint(time.toDouble(), value))
|
||||||
|
}
|
||||||
|
lastTarget = value
|
||||||
|
time += 5 * 60 * 1000L
|
||||||
|
}
|
||||||
|
// final point
|
||||||
|
targetsSeriesArray.add(DataPoint(toTime.toDouble(), lastTarget))
|
||||||
|
// create series
|
||||||
|
addSeries(LineGraphSeries(Array(targetsSeriesArray.size) { i -> targetsSeriesArray[i] }).also {
|
||||||
|
it.isDrawBackground = false
|
||||||
|
it.color = resourceHelper.gc(R.color.tempTargetBackground)
|
||||||
|
it.thickness = 2
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addTreatments(fromTime: Long, endTime: Long) {
|
||||||
|
val filteredTreatments: MutableList<DataPointWithLabelInterface> = ArrayList()
|
||||||
|
val treatments = treatmentsPlugin.treatmentsFromHistory
|
||||||
|
for (tx in treatments.indices) {
|
||||||
|
val t = treatments[tx]
|
||||||
|
if (t.x < fromTime || t.x > endTime) continue
|
||||||
|
if (t.isSMB && !t.isValid) continue
|
||||||
|
t.y = getNearestBg(t.x.toLong())
|
||||||
|
filteredTreatments.add(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProfileSwitch
|
||||||
|
val profileSwitches = treatmentsPlugin.profileSwitchesFromHistory.list
|
||||||
|
for (tx in profileSwitches.indices) {
|
||||||
|
val t: DataPointWithLabelInterface = profileSwitches[tx]
|
||||||
|
if (t.x < fromTime || t.x > endTime) continue
|
||||||
|
filteredTreatments.add(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extended bolus
|
||||||
|
if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) {
|
||||||
|
val extendedBoluses = treatmentsPlugin.extendedBolusesFromHistory.list
|
||||||
|
for (tx in extendedBoluses.indices) {
|
||||||
|
val t: DataPointWithLabelInterface = extendedBoluses[tx]
|
||||||
|
if (t.x + t.duration < fromTime || t.x > endTime) continue
|
||||||
|
if (t.duration == 0L) continue
|
||||||
|
t.y = getNearestBg(t.x.toLong())
|
||||||
|
filteredTreatments.add(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Careportal
|
||||||
|
val careportalEvents = MainApp.getDbHelper().getCareportalEventsFromTime(fromTime - 6 * 60 * 60 * 1000, true)
|
||||||
|
for (tx in careportalEvents.indices) {
|
||||||
|
val t: DataPointWithLabelInterface = careportalEvents[tx]
|
||||||
|
if (t.x + t.duration < fromTime || t.x > endTime) continue
|
||||||
|
t.y = getNearestBg(t.x.toLong())
|
||||||
|
filteredTreatments.add(t)
|
||||||
|
}
|
||||||
|
addSeries(PointsWithLabelGraphSeries(Array(filteredTreatments.size) { i -> filteredTreatments[i] }))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getNearestBg(date: Long): Double {
|
||||||
|
bgReadingsArray?.let { bgReadingsArray ->
|
||||||
|
for (r in bgReadingsArray.indices) {
|
||||||
|
val reading = bgReadingsArray[r]
|
||||||
|
if (reading.date > date) continue
|
||||||
|
return Profile.fromMgdlToUnits(reading.value, units)
|
||||||
|
}
|
||||||
|
return if (bgReadingsArray.isNotEmpty()) Profile.fromMgdlToUnits(bgReadingsArray[0].value, units) else Profile.fromMgdlToUnits(100.0, units)
|
||||||
|
} ?: return Profile.fromMgdlToUnits(100.0, units)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addActivity(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
||||||
|
val actArrayHist: MutableList<ScaledDataPoint> = ArrayList()
|
||||||
|
val actArrayPred: MutableList<ScaledDataPoint> = ArrayList()
|
||||||
|
val now = System.currentTimeMillis().toDouble()
|
||||||
|
val actScale = Scale()
|
||||||
|
var total: IobTotal
|
||||||
|
var maxIAValue = 0.0
|
||||||
|
var time = fromTime
|
||||||
|
while (time <= toTime) {
|
||||||
|
val profile = profileFunction.getProfile(time)
|
||||||
|
if (profile == null) {
|
||||||
|
time += 5 * 60 * 1000L
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
total = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile)
|
||||||
|
val act: Double = total.activity
|
||||||
|
if (time <= now) actArrayHist.add(ScaledDataPoint(time, act, actScale)) else actArrayPred.add(ScaledDataPoint(time, act, actScale))
|
||||||
|
maxIAValue = max(maxIAValue, abs(act))
|
||||||
|
time += 5 * 60 * 1000L
|
||||||
|
}
|
||||||
|
addSeries(FixedLineGraphSeries(Array(actArrayHist.size) { i -> actArrayHist[i] }).also {
|
||||||
|
it.isDrawBackground = false
|
||||||
|
it.color = resourceHelper.gc(R.color.activity)
|
||||||
|
it.thickness = 3
|
||||||
|
})
|
||||||
|
addSeries(FixedLineGraphSeries(Array(actArrayPred.size) { i -> actArrayPred[i] }).also {
|
||||||
|
it.setCustomPaint(Paint().also { paint ->
|
||||||
|
paint.style = Paint.Style.STROKE
|
||||||
|
paint.strokeWidth = 3f
|
||||||
|
paint.pathEffect = DashPathEffect(floatArrayOf(4f, 4f), 0f)
|
||||||
|
paint.color = resourceHelper.gc(R.color.activity)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if (useForScale) {
|
||||||
|
maxY = maxIAValue
|
||||||
|
minY = -maxIAValue
|
||||||
|
}
|
||||||
|
actScale.setMultiplier(maxY * scale / maxIAValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
// scale in % of vertical size (like 0.3)
|
||||||
|
fun addIob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double, showPrediction: Boolean) {
|
||||||
|
val iobSeries: FixedLineGraphSeries<ScaledDataPoint?>
|
||||||
|
val iobArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||||
|
var maxIobValueFound = Double.MIN_VALUE
|
||||||
|
var lastIob = 0.0
|
||||||
|
val iobScale = Scale()
|
||||||
|
var time = fromTime
|
||||||
|
while (time <= toTime) {
|
||||||
|
val profile = profileFunction.getProfile(time)
|
||||||
|
var iob = 0.0
|
||||||
|
if (profile != null) iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(time, profile).iob
|
||||||
|
if (abs(lastIob - iob) > 0.02) {
|
||||||
|
if (abs(lastIob - iob) > 0.2) iobArray.add(ScaledDataPoint(time, lastIob, iobScale))
|
||||||
|
iobArray.add(ScaledDataPoint(time, iob, iobScale))
|
||||||
|
maxIobValueFound = max(maxIobValueFound, abs(iob))
|
||||||
|
lastIob = iob
|
||||||
|
}
|
||||||
|
time += 5 * 60 * 1000L
|
||||||
|
}
|
||||||
|
iobSeries = FixedLineGraphSeries(Array(iobArray.size) { i -> iobArray[i] }).also {
|
||||||
|
it.isDrawBackground = true
|
||||||
|
it.backgroundColor = -0x7f000001 and resourceHelper.gc(R.color.iob) //50%
|
||||||
|
it.color = resourceHelper.gc(R.color.iob)
|
||||||
|
it.thickness = 3
|
||||||
|
}
|
||||||
|
if (showPrediction) {
|
||||||
|
val autosensData = iobCobCalculatorPlugin.getLastAutosensDataSynchronized("GraphData")
|
||||||
|
val lastAutosensResult = autosensData?.autosensResult ?: AutosensResult()
|
||||||
|
val isTempTarget = treatmentsPlugin.getTempTargetFromHistory(System.currentTimeMillis()) != null
|
||||||
|
val iobPred: MutableList<DataPointWithLabelInterface> = ArrayList()
|
||||||
|
val iobPredArray = iobCobCalculatorPlugin.calculateIobArrayForSMB(lastAutosensResult, SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
|
||||||
|
for (i in iobPredArray) {
|
||||||
|
iobPred.add(i.setColor(resourceHelper.gc(R.color.iobPredAS)))
|
||||||
|
maxIobValueFound = max(maxIobValueFound, abs(i.iob))
|
||||||
|
}
|
||||||
|
addSeries(PointsWithLabelGraphSeries(Array(iobPred.size) { i -> iobPred[i] }))
|
||||||
|
val iobPred2: MutableList<DataPointWithLabelInterface> = ArrayList()
|
||||||
|
val iobPredArray2 = iobCobCalculatorPlugin.calculateIobArrayForSMB(AutosensResult(), SMBDefaults.exercise_mode, SMBDefaults.half_basal_exercise_target, isTempTarget)
|
||||||
|
for (i in iobPredArray2) {
|
||||||
|
iobPred2.add(i.setColor(resourceHelper.gc(R.color.iobPred)))
|
||||||
|
maxIobValueFound = max(maxIobValueFound, abs(i.iob))
|
||||||
|
}
|
||||||
|
addSeries(PointsWithLabelGraphSeries(Array(iobPred2.size) { i -> iobPred2[i] }))
|
||||||
|
aapsLogger.debug(LTag.AUTOSENS, "IOB pred for AS=" + DecimalFormatter.to2Decimal(lastAutosensResult.ratio) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredArray))
|
||||||
|
aapsLogger.debug(LTag.AUTOSENS, "IOB pred for AS=" + DecimalFormatter.to2Decimal(1.0) + ": " + iobCobCalculatorPlugin.iobArrayToString(iobPredArray2))
|
||||||
|
}
|
||||||
|
if (useForScale) {
|
||||||
|
maxY = maxIobValueFound
|
||||||
|
minY = -maxIobValueFound
|
||||||
|
}
|
||||||
|
iobScale.setMultiplier(maxY * scale / maxIobValueFound)
|
||||||
|
addSeries(iobSeries)
|
||||||
|
}
|
||||||
|
|
||||||
|
// scale in % of vertical size (like 0.3)
|
||||||
|
fun addCob(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
||||||
|
val minFailOverActiveList: MutableList<DataPointWithLabelInterface> = ArrayList()
|
||||||
|
val cobArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||||
|
var maxCobValueFound = 0.0
|
||||||
|
var lastCob = 0
|
||||||
|
val cobScale = Scale()
|
||||||
|
var time = fromTime
|
||||||
|
while (time <= toTime) {
|
||||||
|
iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData ->
|
||||||
|
val cob = autosensData.cob.toInt()
|
||||||
|
if (cob != lastCob) {
|
||||||
|
if (autosensData.carbsFromBolus > 0) cobArray.add(ScaledDataPoint(time, lastCob.toDouble(), cobScale))
|
||||||
|
cobArray.add(ScaledDataPoint(time, cob.toDouble(), cobScale))
|
||||||
|
maxCobValueFound = max(maxCobValueFound, cob.toDouble())
|
||||||
|
lastCob = cob
|
||||||
|
}
|
||||||
|
if (autosensData.failoverToMinAbsorbtionRate) {
|
||||||
|
autosensData.setScale(cobScale)
|
||||||
|
autosensData.setChartTime(time)
|
||||||
|
minFailOverActiveList.add(autosensData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time += 5 * 60 * 1000L
|
||||||
|
}
|
||||||
|
|
||||||
|
// COB
|
||||||
|
addSeries(FixedLineGraphSeries(Array(cobArray.size) { i -> cobArray[i] }).also {
|
||||||
|
it.isDrawBackground = true
|
||||||
|
it.backgroundColor = -0x7f000001 and resourceHelper.gc(R.color.cob) //50%
|
||||||
|
it.color = resourceHelper.gc(R.color.cob)
|
||||||
|
it.thickness = 3
|
||||||
|
})
|
||||||
|
if (useForScale) {
|
||||||
|
maxY = maxCobValueFound
|
||||||
|
minY = 0.0
|
||||||
|
}
|
||||||
|
cobScale.setMultiplier(maxY * scale / maxCobValueFound)
|
||||||
|
addSeries(PointsWithLabelGraphSeries(Array(minFailOverActiveList.size) { i -> minFailOverActiveList[i] }))
|
||||||
|
}
|
||||||
|
|
||||||
|
// scale in % of vertical size (like 0.3)
|
||||||
|
fun addDeviations(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
||||||
|
class DeviationDataPoint(x: Double, y: Double, var color: Int, scale: Scale) : ScaledDataPoint(x, y, scale)
|
||||||
|
|
||||||
|
val devArray: MutableList<DeviationDataPoint> = ArrayList()
|
||||||
|
var maxDevValueFound = 0.0
|
||||||
|
val devScale = Scale()
|
||||||
|
var time = fromTime
|
||||||
|
while (time <= toTime) {
|
||||||
|
iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData ->
|
||||||
|
var color = resourceHelper.gc(R.color.deviationblack) // "="
|
||||||
|
if (autosensData.type == "" || autosensData.type == "non-meal") {
|
||||||
|
if (autosensData.pastSensitivity == "C") color = resourceHelper.gc(R.color.deviationgrey)
|
||||||
|
if (autosensData.pastSensitivity == "+") color = resourceHelper.gc(R.color.deviationgreen)
|
||||||
|
if (autosensData.pastSensitivity == "-") color = resourceHelper.gc(R.color.deviationred)
|
||||||
|
} else if (autosensData.type == "uam") {
|
||||||
|
color = resourceHelper.gc(R.color.uam)
|
||||||
|
} else if (autosensData.type == "csf") {
|
||||||
|
color = resourceHelper.gc(R.color.deviationgrey)
|
||||||
|
}
|
||||||
|
devArray.add(DeviationDataPoint(time.toDouble(), autosensData.deviation, color, devScale))
|
||||||
|
maxDevValueFound = max(maxDevValueFound, abs(autosensData.deviation))
|
||||||
|
}
|
||||||
|
time += 5 * 60 * 1000L
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEVIATIONS
|
||||||
|
addSeries(BarGraphSeries(Array(devArray.size) { i -> devArray[i] }).also {
|
||||||
|
it.setValueDependentColor { data: DeviationDataPoint -> data.color }
|
||||||
|
})
|
||||||
|
if (useForScale) {
|
||||||
|
maxY = maxDevValueFound
|
||||||
|
minY = -maxY
|
||||||
|
}
|
||||||
|
devScale.setMultiplier(maxY * scale / maxDevValueFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
// scale in % of vertical size (like 0.3)
|
||||||
|
fun addRatio(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
||||||
|
val ratioArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||||
|
var maxRatioValueFound = Double.MIN_VALUE
|
||||||
|
var minRatioValueFound = Double.MAX_VALUE
|
||||||
|
val ratioScale = Scale()
|
||||||
|
var time = fromTime
|
||||||
|
while (time <= toTime) {
|
||||||
|
iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData ->
|
||||||
|
ratioArray.add(ScaledDataPoint(time, autosensData.autosensResult.ratio - 1, ratioScale))
|
||||||
|
maxRatioValueFound = max(maxRatioValueFound, autosensData.autosensResult.ratio - 1)
|
||||||
|
minRatioValueFound = min(minRatioValueFound, autosensData.autosensResult.ratio - 1)
|
||||||
|
}
|
||||||
|
time += 5 * 60 * 1000L
|
||||||
|
}
|
||||||
|
|
||||||
|
// RATIOS
|
||||||
|
addSeries(LineGraphSeries(Array(ratioArray.size) { i -> ratioArray[i] }).also {
|
||||||
|
it.color = resourceHelper.gc(R.color.ratio)
|
||||||
|
it.thickness = 3
|
||||||
|
})
|
||||||
|
if (useForScale) {
|
||||||
|
maxY = max(maxRatioValueFound, abs(minRatioValueFound))
|
||||||
|
minY = -maxY
|
||||||
|
}
|
||||||
|
ratioScale.setMultiplier(maxY * scale / max(maxRatioValueFound, abs(minRatioValueFound)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// scale in % of vertical size (like 0.3)
|
||||||
|
fun addDeviationSlope(fromTime: Long, toTime: Long, useForScale: Boolean, scale: Double) {
|
||||||
|
val dsMaxArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||||
|
val dsMinArray: MutableList<ScaledDataPoint> = ArrayList()
|
||||||
|
var maxFromMaxValueFound = 0.0
|
||||||
|
var maxFromMinValueFound = 0.0
|
||||||
|
val dsMaxScale = Scale()
|
||||||
|
val dsMinScale = Scale()
|
||||||
|
var time = fromTime
|
||||||
|
while (time <= toTime) {
|
||||||
|
iobCobCalculatorPlugin.getAutosensData(time)?.let { autosensData ->
|
||||||
|
dsMaxArray.add(ScaledDataPoint(time, autosensData.slopeFromMaxDeviation, dsMaxScale))
|
||||||
|
dsMinArray.add(ScaledDataPoint(time, autosensData.slopeFromMinDeviation, dsMinScale))
|
||||||
|
maxFromMaxValueFound = max(maxFromMaxValueFound, abs(autosensData.slopeFromMaxDeviation))
|
||||||
|
maxFromMinValueFound = max(maxFromMinValueFound, abs(autosensData.slopeFromMinDeviation))
|
||||||
|
}
|
||||||
|
time += 5 * 60 * 1000L
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slopes
|
||||||
|
addSeries(LineGraphSeries(Array(dsMaxArray.size) { i -> dsMaxArray[i] }).also {
|
||||||
|
it.color = resourceHelper.gc(R.color.devslopepos)
|
||||||
|
it.thickness = 3
|
||||||
|
})
|
||||||
|
addSeries(LineGraphSeries(Array(dsMinArray.size) { i -> dsMinArray[i] }).also {
|
||||||
|
it.color = resourceHelper.gc(R.color.devslopeneg)
|
||||||
|
it.thickness = 3
|
||||||
|
})
|
||||||
|
if (useForScale) {
|
||||||
|
maxY = max(maxFromMaxValueFound, maxFromMinValueFound)
|
||||||
|
minY = -maxY
|
||||||
|
}
|
||||||
|
dsMaxScale.setMultiplier(maxY * scale / maxFromMaxValueFound)
|
||||||
|
dsMinScale.setMultiplier(maxY * scale / maxFromMinValueFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
// scale in % of vertical size (like 0.3)
|
||||||
|
fun addNowLine(now: Long) {
|
||||||
|
val nowPoints = arrayOf(
|
||||||
|
DataPoint(now.toDouble(), 0.0),
|
||||||
|
DataPoint(now.toDouble(), maxY)
|
||||||
|
)
|
||||||
|
addSeries(LineGraphSeries(nowPoints).also {
|
||||||
|
it.isDrawDataPoints = false
|
||||||
|
// custom paint to make a dotted line
|
||||||
|
it.setCustomPaint(Paint().also { paint ->
|
||||||
|
paint.style = Paint.Style.STROKE
|
||||||
|
paint.strokeWidth = 2f
|
||||||
|
paint.pathEffect = DashPathEffect(floatArrayOf(10f, 20f), 0f)
|
||||||
|
paint.color = Color.WHITE
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun formatAxis(fromTime: Long, endTime: Long) {
|
||||||
|
graph.viewport.setMaxX(endTime.toDouble())
|
||||||
|
graph.viewport.setMinX(fromTime.toDouble())
|
||||||
|
graph.viewport.isXAxisBoundsManual = true
|
||||||
|
graph.gridLabelRenderer.labelFormatter = TimeAsXAxisLabelFormatter("HH")
|
||||||
|
graph.gridLabelRenderer.numHorizontalLabels = 7 // only 7 because of the space
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addSeries(s: Series<*>) = series.add(s)
|
||||||
|
|
||||||
|
fun performUpdate() {
|
||||||
|
// clear old data
|
||||||
|
graph.series.clear()
|
||||||
|
|
||||||
|
// add pre calculated series
|
||||||
|
for (s in series) {
|
||||||
|
if (!s.isEmpty) {
|
||||||
|
s.onGraphViewAttached(graph)
|
||||||
|
graph.series.add(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var step = 1.0
|
||||||
|
if (maxY < 1) step = 0.1
|
||||||
|
graph.viewport.setMaxY(Round.ceilTo(maxY, step))
|
||||||
|
graph.viewport.setMinY(Round.floorTo(minY, step))
|
||||||
|
graph.viewport.isYAxisBoundsManual = true
|
||||||
|
|
||||||
|
// draw it
|
||||||
|
graph.onDataChanged(false, false)
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,12 @@ public class ScaledDataPoint implements DataPointInterface, Serializable {
|
||||||
this.scale = scale;
|
this.scale = scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ScaledDataPoint(long x, double y, Scale scale) {
|
||||||
|
this.x=x;
|
||||||
|
this.y=y;
|
||||||
|
this.scale = scale;
|
||||||
|
}
|
||||||
|
|
||||||
public ScaledDataPoint(Date x, double y, Scale scale) {
|
public ScaledDataPoint(Date x, double y, Scale scale) {
|
||||||
this.x = x.getTime();
|
this.x = x.getTime();
|
||||||
this.y = y;
|
this.y = y;
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
package info.nightscout.androidaps.plugins.general.overview.notifications;
|
|
||||||
|
|
||||||
import android.app.IntentService;
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.Intent;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.MainApp;
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification;
|
|
||||||
|
|
||||||
public class DismissNotificationService extends IntentService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an IntentService. Invoked by your subclass's constructor.
|
|
||||||
*
|
|
||||||
* @param name Used to name the worker thread, important only for debugging.
|
|
||||||
*/
|
|
||||||
public DismissNotificationService(String name) {
|
|
||||||
super(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DismissNotificationService() {
|
|
||||||
super("DismissNotificationService");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onHandleIntent(@Nullable Intent intent) {
|
|
||||||
RxBus.Companion.getINSTANCE().send(new EventDismissNotification(intent.getIntExtra("alertID", -1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PendingIntent deleteIntent(int id) {
|
|
||||||
Intent intent = new Intent(MainApp.instance(), DismissNotificationService.class);
|
|
||||||
intent.putExtra("alertID", id);
|
|
||||||
return PendingIntent.getService(MainApp.instance(), id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package info.nightscout.androidaps.plugins.general.overview.notifications
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import dagger.android.DaggerIntentService
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class DismissNotificationService : DaggerIntentService(DismissNotificationService::class.simpleName) {
|
||||||
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
|
|
||||||
|
override fun onHandleIntent(intent: Intent) {
|
||||||
|
rxBus.send(EventDismissNotification(intent.getIntExtra("alertID", -1)))
|
||||||
|
}
|
||||||
|
}
|
|
@ -64,11 +64,11 @@ public class Notification {
|
||||||
public static final int DST_IN_24H = 50;
|
public static final int DST_IN_24H = 50;
|
||||||
public static final int DISKFULL = 51;
|
public static final int DISKFULL = 51;
|
||||||
public static final int OLDVERSION = 52;
|
public static final int OLDVERSION = 52;
|
||||||
public static final int USERMESSAGE = 53;
|
|
||||||
public static final int OVER_24H_TIME_CHANGE_REQUESTED = 54;
|
public static final int OVER_24H_TIME_CHANGE_REQUESTED = 54;
|
||||||
public static final int INVALID_VERSION = 55;
|
public static final int INVALID_VERSION = 55;
|
||||||
public static final int PERMISSION_SYSTEM_WINDOW = 56;
|
public static final int PERMISSION_SYSTEM_WINDOW = 56;
|
||||||
|
|
||||||
|
public static final int USERMESSAGE = 1000;
|
||||||
|
|
||||||
public int id;
|
public int id;
|
||||||
public long date;
|
public long date;
|
||||||
|
|
|
@ -3,6 +3,7 @@ package info.nightscout.androidaps.plugins.general.overview.notifications
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
|
@ -16,7 +17,6 @@ import android.widget.TextView
|
||||||
import androidx.cardview.widget.CardView
|
import androidx.cardview.widget.CardView
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import info.nightscout.androidaps.MainApp
|
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
@ -36,7 +36,7 @@ class NotificationStore @Inject constructor(
|
||||||
private val sp: SP,
|
private val sp: SP,
|
||||||
private val rxBus: RxBusWrapper,
|
private val rxBus: RxBusWrapper,
|
||||||
private val resourceHelper: ResourceHelper,
|
private val resourceHelper: ResourceHelper,
|
||||||
private val mainApp: MainApp
|
private val context: Context
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var store: MutableList<Notification> = ArrayList()
|
var store: MutableList<Notification> = ArrayList()
|
||||||
|
@ -66,15 +66,15 @@ class NotificationStore @Inject constructor(
|
||||||
if (sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, false) && n !is NotificationWithAction) {
|
if (sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, false) && n !is NotificationWithAction) {
|
||||||
raiseSystemNotification(n)
|
raiseSystemNotification(n)
|
||||||
if (usesChannels && n.soundId != null && n.soundId != 0) {
|
if (usesChannels && n.soundId != null && n.soundId != 0) {
|
||||||
val alarm = Intent(mainApp, AlarmSoundService::class.java)
|
val alarm = Intent(context, AlarmSoundService::class.java)
|
||||||
alarm.putExtra("soundid", n.soundId)
|
alarm.putExtra("soundid", n.soundId)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) mainApp.startForegroundService(alarm) else mainApp.startService(alarm)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(alarm) else context.startService(alarm)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (n.soundId != null && n.soundId != 0) {
|
if (n.soundId != null && n.soundId != 0) {
|
||||||
val alarm = Intent(mainApp, AlarmSoundService::class.java)
|
val alarm = Intent(context, AlarmSoundService::class.java)
|
||||||
alarm.putExtra("soundid", n.soundId)
|
alarm.putExtra("soundid", n.soundId)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) mainApp.startForegroundService(alarm) else mainApp.startService(alarm)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(alarm) else context.startService(alarm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Collections.sort(store, NotificationComparator())
|
Collections.sort(store, NotificationComparator())
|
||||||
|
@ -85,8 +85,8 @@ class NotificationStore @Inject constructor(
|
||||||
for (i in store.indices) {
|
for (i in store.indices) {
|
||||||
if (store[i].id == id) {
|
if (store[i].id == id) {
|
||||||
if (store[i].soundId != null) {
|
if (store[i].soundId != null) {
|
||||||
val alarm = Intent(mainApp, AlarmSoundService::class.java)
|
val alarm = Intent(context, AlarmSoundService::class.java)
|
||||||
mainApp.stopService(alarm)
|
context.stopService(alarm)
|
||||||
}
|
}
|
||||||
store.removeAt(i)
|
store.removeAt(i)
|
||||||
return true
|
return true
|
||||||
|
@ -108,16 +108,16 @@ class NotificationStore @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun raiseSystemNotification(n: Notification) {
|
private fun raiseSystemNotification(n: Notification) {
|
||||||
val mgr = mainApp.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
val mgr = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
val largeIcon = resourceHelper.decodeResource(resourceHelper.getIcon())
|
val largeIcon = resourceHelper.decodeResource(resourceHelper.getIcon())
|
||||||
val smallIcon = resourceHelper.getNotificationIcon()
|
val smallIcon = resourceHelper.getNotificationIcon()
|
||||||
val sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM)
|
val sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM)
|
||||||
val notificationBuilder = NotificationCompat.Builder(mainApp, CHANNEL_ID)
|
val notificationBuilder = NotificationCompat.Builder(context, CHANNEL_ID)
|
||||||
.setSmallIcon(smallIcon)
|
.setSmallIcon(smallIcon)
|
||||||
.setLargeIcon(largeIcon)
|
.setLargeIcon(largeIcon)
|
||||||
.setContentText(n.text)
|
.setContentText(n.text)
|
||||||
.setPriority(NotificationCompat.PRIORITY_MAX)
|
.setPriority(NotificationCompat.PRIORITY_MAX)
|
||||||
.setDeleteIntent(DismissNotificationService.deleteIntent(n.id))
|
.setDeleteIntent(deleteIntent(n.id))
|
||||||
if (n.level == Notification.URGENT) {
|
if (n.level == Notification.URGENT) {
|
||||||
notificationBuilder.setVibrate(longArrayOf(1000, 1000, 1000, 1000))
|
notificationBuilder.setVibrate(longArrayOf(1000, 1000, 1000, 1000))
|
||||||
.setContentTitle(resourceHelper.gs(R.string.urgent_alarm))
|
.setContentTitle(resourceHelper.gs(R.string.urgent_alarm))
|
||||||
|
@ -129,10 +129,16 @@ class NotificationStore @Inject constructor(
|
||||||
mgr.notify(n.id, notificationBuilder.build())
|
mgr.notify(n.id, notificationBuilder.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun deleteIntent(id: Int): PendingIntent {
|
||||||
|
val intent = Intent(context, DismissNotificationService::class.java)
|
||||||
|
intent.putExtra("alertID", id)
|
||||||
|
return PendingIntent.getService(context, id, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
}
|
||||||
|
|
||||||
fun createNotificationChannel() {
|
fun createNotificationChannel() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
usesChannels = true
|
usesChannels = true
|
||||||
val mNotificationManager = mainApp.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
val mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
@SuppressLint("WrongConstant") val channel = NotificationChannel(CHANNEL_ID,
|
@SuppressLint("WrongConstant") val channel = NotificationChannel(CHANNEL_ID,
|
||||||
CHANNEL_ID,
|
CHANNEL_ID,
|
||||||
NotificationManager.IMPORTANCE_HIGH)
|
NotificationManager.IMPORTANCE_HIGH)
|
||||||
|
@ -159,17 +165,19 @@ class NotificationStore @Inject constructor(
|
||||||
clone.addAll(store)
|
clone.addAll(store)
|
||||||
return clone
|
return clone
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
private fun unSnooze() {
|
/*
|
||||||
if (sp.getBoolean(R.string.key_nsalarm_staledata, false)) {
|
private fun unSnooze() {
|
||||||
val notification = Notification(Notification.NSALARM, resourceHelper.gs(R.string.nsalarm_staledata), Notification.URGENT)
|
if (sp.getBoolean(R.string.key_nsalarm_staledata, false)) {
|
||||||
sp.putLong(R.string.key_snoozedTo, System.currentTimeMillis())
|
val notification = Notification(Notification.NSALARM, resourceHelper.gs(R.string.nsalarm_staledata), Notification.URGENT)
|
||||||
add(notification)
|
sp.putLong(R.string.key_snoozedTo, System.currentTimeMillis())
|
||||||
aapsLogger.debug(LTag.NOTIFICATION, "Snoozed to current time and added back notification!")
|
add(notification)
|
||||||
|
aapsLogger.debug(LTag.NOTIFICATION, "Snoozed to current time and added back notification!")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
*/
|
||||||
*/
|
|
||||||
inner class NotificationRecyclerViewAdapter internal constructor(private val notificationsList: List<Notification>) : RecyclerView.Adapter<NotificationRecyclerViewAdapter.NotificationsViewHolder>() {
|
inner class NotificationRecyclerViewAdapter internal constructor(private val notificationsList: List<Notification>) : RecyclerView.Adapter<NotificationRecyclerViewAdapter.NotificationsViewHolder>() {
|
||||||
|
|
||||||
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): NotificationsViewHolder {
|
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): NotificationsViewHolder {
|
||||||
val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.overview_notification_item, viewGroup, false)
|
val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.overview_notification_item, viewGroup, false)
|
||||||
return NotificationsViewHolder(v)
|
return NotificationsViewHolder(v)
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package info.nightscout.androidaps.plugins.general.overview.notifications
|
||||||
|
|
||||||
|
class NotificationUserMessage (text :String): Notification() {
|
||||||
|
|
||||||
|
init {
|
||||||
|
var hash = text.hashCode()
|
||||||
|
if (hash < USERMESSAGE) hash += USERMESSAGE
|
||||||
|
id = hash
|
||||||
|
this.text = text
|
||||||
|
level = URGENT
|
||||||
|
}
|
||||||
|
}
|
|
@ -703,13 +703,11 @@ class SmsCommunicatorPlugin @Inject constructor(
|
||||||
var grams = SafeParse.stringToInt(splitted[1])
|
var grams = SafeParse.stringToInt(splitted[1])
|
||||||
var time = DateUtil.now()
|
var time = DateUtil.now()
|
||||||
if (splitted.size > 2) {
|
if (splitted.size > 2) {
|
||||||
val seconds = DateUtil.toSeconds(splitted[2].toUpperCase(Locale.getDefault()))
|
time = DateUtil.toTodayTime(splitted[2].toUpperCase(Locale.getDefault()))
|
||||||
val midnight = MidnightTime.calc()
|
if (time == 0L) {
|
||||||
if (seconds == 0 && (!splitted[2].startsWith("00:00") || !splitted[2].startsWith("12:00"))) {
|
|
||||||
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
time = midnight + T.secs(seconds.toLong()).msecs()
|
|
||||||
}
|
}
|
||||||
grams = constraintChecker.applyCarbsConstraints(Constraint(grams)).value()
|
grams = constraintChecker.applyCarbsConstraints(Constraint(grams)).value()
|
||||||
if (grams == 0) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
if (grams == 0) sendSMS(Sms(receivedSms.phoneNumber, resourceHelper.gs(R.string.wrongformat)))
|
||||||
|
|
|
@ -25,8 +25,7 @@ import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolR
|
||||||
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolStatus
|
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolStatus
|
||||||
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolUpdateGUI
|
import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolUpdateGUI
|
||||||
import info.nightscout.androidaps.plugins.general.tidepool.utils.RateLimit
|
import info.nightscout.androidaps.plugins.general.tidepool.utils.RateLimit
|
||||||
import info.nightscout.androidaps.receivers.ChargingStateReceiver
|
import info.nightscout.androidaps.receivers.ReceiverStatusStore
|
||||||
import info.nightscout.androidaps.receivers.NetworkChangeReceiver
|
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.HtmlHelper
|
import info.nightscout.androidaps.utils.HtmlHelper
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
|
@ -50,7 +49,9 @@ class TidepoolPlugin @Inject constructor(
|
||||||
private val fabricPrivacy: FabricPrivacy,
|
private val fabricPrivacy: FabricPrivacy,
|
||||||
private val tidepoolUploader: TidepoolUploader,
|
private val tidepoolUploader: TidepoolUploader,
|
||||||
private val uploadChunk: UploadChunk,
|
private val uploadChunk: UploadChunk,
|
||||||
private val sp: SP
|
private val sp: SP,
|
||||||
|
private val rateLimit: RateLimit,
|
||||||
|
private val receiverStatusStore: ReceiverStatusStore
|
||||||
) : PluginBase(PluginDescription()
|
) : PluginBase(PluginDescription()
|
||||||
.mainType(PluginType.GENERAL)
|
.mainType(PluginType.GENERAL)
|
||||||
.pluginName(R.string.tidepool)
|
.pluginName(R.string.tidepool)
|
||||||
|
@ -101,9 +102,9 @@ class TidepoolPlugin @Inject constructor(
|
||||||
if (bgReading!!.date < uploadChunk.getLastEnd())
|
if (bgReading!!.date < uploadChunk.getLastEnd())
|
||||||
uploadChunk.setLastEnd(bgReading.date)
|
uploadChunk.setLastEnd(bgReading.date)
|
||||||
if (isEnabled(PluginType.GENERAL)
|
if (isEnabled(PluginType.GENERAL)
|
||||||
&& (!sp.getBoolean(R.string.key_tidepool_only_while_charging, false) || ChargingStateReceiver.isCharging())
|
&& (!sp.getBoolean(R.string.key_tidepool_only_while_charging, false) || receiverStatusStore.isCharging)
|
||||||
&& (!sp.getBoolean(R.string.key_tidepool_only_while_unmetered, false) || NetworkChangeReceiver.isWifiConnected())
|
&& (!sp.getBoolean(R.string.key_tidepool_only_while_unmetered, false) || receiverStatusStore.isWifiConnected)
|
||||||
&& RateLimit.rateLimit("tidepool-new-data-upload", T.mins(4).secs().toInt()))
|
&& rateLimit.rateLimit("tidepool-new-data-upload", T.mins(4).secs().toInt()))
|
||||||
doUpload()
|
doUpload()
|
||||||
}, {
|
}, {
|
||||||
fabricPrivacy.logException(it)
|
fabricPrivacy.logException(it)
|
||||||
|
|
|
@ -1,32 +1,22 @@
|
||||||
package info.nightscout.androidaps.plugins.general.tidepool.comm
|
package info.nightscout.androidaps.plugins.general.tidepool.comm
|
||||||
|
|
||||||
import info.nightscout.androidaps.logging.L
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.StacktraceLoggerWrapper
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import okio.Buffer
|
import okio.Buffer
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
class InfoInterceptor(tag: String) : Interceptor {
|
class InfoInterceptor(val tag: String = "interceptor", val aapsLogger: AAPSLogger) : Interceptor {
|
||||||
|
|
||||||
private val log = StacktraceLoggerWrapper.getLogger(L.TIDEPOOL)
|
|
||||||
private var tag = "interceptor"
|
|
||||||
|
|
||||||
init {
|
|
||||||
this.tag = tag
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun intercept(chain: Interceptor.Chain): Response {
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
val request = chain.request()
|
val request = chain.request()
|
||||||
request.body?.let {
|
request.body?.let {
|
||||||
if (L.isEnabled(L.TIDEPOOL)) {
|
aapsLogger.debug(LTag.TIDEPOOL, "Interceptor Body size: " + it.contentLength())
|
||||||
log.debug("Interceptor Body size: " + it.contentLength())
|
val requestBuffer = Buffer()
|
||||||
val requestBuffer = Buffer()
|
it.writeTo(requestBuffer)
|
||||||
it.writeTo(requestBuffer)
|
aapsLogger.debug(LTag.TIDEPOOL, "Interceptor Body: " + requestBuffer.readUtf8())
|
||||||
log.debug("Interceptor Body: " + requestBuffer.readUtf8())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return chain.proceed(request)
|
return chain.proceed(request)
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ class TidepoolUploader @Inject constructor(
|
||||||
|
|
||||||
val client = OkHttpClient.Builder()
|
val client = OkHttpClient.Builder()
|
||||||
.addInterceptor(httpLoggingInterceptor)
|
.addInterceptor(httpLoggingInterceptor)
|
||||||
.addInterceptor(InfoInterceptor(TidepoolUploader::class.java.name))
|
.addInterceptor(InfoInterceptor(TidepoolUploader::class.java.name, aapsLogger))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
retrofit = Retrofit.Builder()
|
retrofit = Retrofit.Builder()
|
||||||
|
|
|
@ -1,23 +1,13 @@
|
||||||
package info.nightscout.androidaps.plugins.general.tidepool.events
|
package info.nightscout.androidaps.plugins.general.tidepool.events
|
||||||
|
|
||||||
import info.nightscout.androidaps.events.Event
|
import info.nightscout.androidaps.events.Event
|
||||||
import info.nightscout.androidaps.logging.L
|
|
||||||
import info.nightscout.androidaps.logging.StacktraceLoggerWrapper
|
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class EventTidepoolStatus(val status: String) : Event() {
|
class EventTidepoolStatus(val status: String) : Event() {
|
||||||
private val log = StacktraceLoggerWrapper.getLogger(L.TIDEPOOL)
|
|
||||||
|
|
||||||
var date: Long = DateUtil.now()
|
var date: Long = DateUtil.now()
|
||||||
|
|
||||||
init {
|
|
||||||
if (L.isEnabled(L.TIDEPOOL))
|
|
||||||
log.debug("New status: $status")
|
|
||||||
}
|
|
||||||
|
|
||||||
private var timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
|
private var timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
|
||||||
|
|
||||||
fun toPreparedHtml(): StringBuilder {
|
fun toPreparedHtml(): StringBuilder {
|
||||||
|
@ -29,5 +19,4 @@ class EventTidepoolStatus(val status: String) : Event() {
|
||||||
stringBuilder.append("<br>")
|
stringBuilder.append("<br>")
|
||||||
return stringBuilder
|
return stringBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,26 +1,27 @@
|
||||||
package info.nightscout.androidaps.plugins.general.tidepool.utils
|
package info.nightscout.androidaps.plugins.general.tidepool.utils
|
||||||
|
|
||||||
import info.nightscout.androidaps.logging.L
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.StacktraceLoggerWrapper
|
import info.nightscout.androidaps.logging.LTag
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
object RateLimit {
|
@Singleton
|
||||||
|
class RateLimit @Inject constructor(
|
||||||
|
val aapsLogger: AAPSLogger
|
||||||
|
) {
|
||||||
|
|
||||||
private val rateLimits = HashMap<String, Long>()
|
private val rateLimits = HashMap<String, Long>()
|
||||||
|
|
||||||
private val log = StacktraceLoggerWrapper.getLogger(L.TIDEPOOL)
|
|
||||||
|
|
||||||
// return true if below rate limit
|
// return true if below rate limit
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun rateLimit(name: String, seconds: Int): Boolean {
|
fun rateLimit(name: String, seconds: Int): Boolean {
|
||||||
// check if over limit
|
// check if over limit
|
||||||
rateLimits[name]?.let {
|
rateLimits[name]?.let {
|
||||||
if (DateUtil.now() - it < T.secs(seconds.toLong()).msecs()) {
|
if (DateUtil.now() - it < T.secs(seconds.toLong()).msecs()) {
|
||||||
if (L.isEnabled(L.TIDEPOOL))
|
aapsLogger.debug(LTag.TIDEPOOL, "$name rate limited: $seconds seconds")
|
||||||
log.debug("$name rate limited: $seconds seconds")
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,17 +2,14 @@ package info.nightscout.androidaps.plugins.iob.iobCobCalculator;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import info.nightscout.androidaps.logging.L;
|
import info.nightscout.androidaps.logging.LTag;
|
||||||
import info.nightscout.androidaps.logging.StacktraceLoggerWrapper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by mike on 06.01.2017.
|
* Created by mike on 06.01.2017.
|
||||||
*/
|
*/
|
||||||
public class AutosensResult {
|
public class AutosensResult {
|
||||||
private static Logger log = StacktraceLoggerWrapper.getLogger(L.AUTOSENS);
|
|
||||||
|
|
||||||
//default values to show when autosens algorithm is not called
|
//default values to show when autosens algorithm is not called
|
||||||
public double ratio = 1d;
|
public double ratio = 1d;
|
||||||
|
@ -30,7 +27,7 @@ public class AutosensResult {
|
||||||
ret.put("sensResult", sensResult);
|
ret.put("sensResult", sensResult);
|
||||||
ret.put("ratio", ratio);
|
ret.put("ratio", ratio);
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
log.error("Unhandled exception", e);
|
LoggerFactory.getLogger(LTag.CORE.getTag()).error("Unhandled exception", e);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,17 +196,15 @@ public class IobCobOref1Thread extends Thread {
|
||||||
try {
|
try {
|
||||||
for (; past < 12; past++) {
|
for (; past < 12; past++) {
|
||||||
AutosensData ad = autosensDataTable.valueAt(initialIndex + past);
|
AutosensData ad = autosensDataTable.valueAt(initialIndex + past);
|
||||||
if (L.isEnabled(L.AUTOSENS)) {
|
aapsLogger.debug(LTag.AUTOSENS, ">>>>> past=" + past + " ad=" + (ad != null ? ad.toString() : null));
|
||||||
aapsLogger.debug(">>>>> past=" + past + " ad=" + (ad != null ? ad.toString() : null));
|
if (ad == null) {
|
||||||
if (ad == null) {
|
aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString());
|
||||||
aapsLogger.debug(autosensDataTable.toString());
|
aapsLogger.debug(LTag.AUTOSENS, bucketed_data.toString());
|
||||||
aapsLogger.debug(bucketed_data.toString());
|
aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.getBgReadings().toString());
|
||||||
aapsLogger.debug(iobCobCalculatorPlugin.getBgReadings().toString());
|
Notification notification = new Notification(Notification.SENDLOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW);
|
||||||
Notification notification = new Notification(Notification.SENDLOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW);
|
rxBus.send(new EventNewNotification(notification));
|
||||||
rxBus.send(new EventNewNotification(notification));
|
sp.putBoolean("log_AUTOSENS", true);
|
||||||
sp.putBoolean("log_AUTOSENS", true);
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// let it here crash on NPE to get more data as i cannot reproduce this bug
|
// let it here crash on NPE to get more data as i cannot reproduce this bug
|
||||||
double deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5;
|
double deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5;
|
||||||
|
|
|
@ -21,7 +21,6 @@ import info.nightscout.androidaps.events.Event;
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider;
|
||||||
import info.nightscout.androidaps.interfaces.PluginType;
|
import info.nightscout.androidaps.interfaces.PluginType;
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||||
import info.nightscout.androidaps.logging.L;
|
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
import info.nightscout.androidaps.logging.LTag;
|
||||||
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults;
|
import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults;
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||||
|
@ -193,17 +192,15 @@ public class IobCobThread extends Thread {
|
||||||
try {
|
try {
|
||||||
for (; past < 12; past++) {
|
for (; past < 12; past++) {
|
||||||
AutosensData ad = autosensDataTable.valueAt(initialIndex + past);
|
AutosensData ad = autosensDataTable.valueAt(initialIndex + past);
|
||||||
if (L.isEnabled(L.AUTOSENS)) {
|
aapsLogger.debug(LTag.AUTOSENS, ">>>>> past=" + past + " ad=" + (ad != null ? ad.toString() : null));
|
||||||
aapsLogger.debug(">>>>> past=" + past + " ad=" + (ad != null ? ad.toString() : null));
|
if (ad == null) {
|
||||||
if (ad == null) {
|
aapsLogger.debug(LTag.AUTOSENS, autosensDataTable.toString());
|
||||||
aapsLogger.debug(autosensDataTable.toString());
|
aapsLogger.debug(LTag.AUTOSENS, bucketed_data.toString());
|
||||||
aapsLogger.debug(bucketed_data.toString());
|
aapsLogger.debug(LTag.AUTOSENS, iobCobCalculatorPlugin.getBgReadings().toString());
|
||||||
aapsLogger.debug(iobCobCalculatorPlugin.getBgReadings().toString());
|
Notification notification = new Notification(Notification.SENDLOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW);
|
||||||
Notification notification = new Notification(Notification.SENDLOGFILES, resourceHelper.gs(R.string.sendlogfiles), Notification.LOW);
|
rxBus.send(new EventNewNotification(notification));
|
||||||
rxBus.send(new EventNewNotification(notification));
|
sp.putBoolean("log_AUTOSENS", true);
|
||||||
sp.putBoolean("log_AUTOSENS", true);
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// let it here crash on NPE to get more data as i cannot reproduce this bug
|
// let it here crash on NPE to get more data as i cannot reproduce this bug
|
||||||
double deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5;
|
double deviationSlope = (ad.avgDeviation - avgDeviation) / (ad.time - bgTime) * 1000 * 60 * 5;
|
||||||
|
|
|
@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.pump.danaR.services;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothSocket;
|
import android.bluetooth.BluetoothSocket;
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
@ -20,6 +19,9 @@ import dagger.android.HasAndroidInjector;
|
||||||
import info.nightscout.androidaps.R;
|
import info.nightscout.androidaps.R;
|
||||||
import info.nightscout.androidaps.data.Profile;
|
import info.nightscout.androidaps.data.Profile;
|
||||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||||
|
import info.nightscout.androidaps.events.EventAppExit;
|
||||||
|
import info.nightscout.androidaps.events.EventBTChange;
|
||||||
|
import info.nightscout.androidaps.events.EventPreferenceChange;
|
||||||
import info.nightscout.androidaps.events.EventPumpStatusChanged;
|
import info.nightscout.androidaps.events.EventPumpStatusChanged;
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
import info.nightscout.androidaps.logging.LTag;
|
||||||
|
@ -41,9 +43,12 @@ import info.nightscout.androidaps.plugins.pump.danaR.comm.MsgPCCommStop;
|
||||||
import info.nightscout.androidaps.plugins.pump.danaR.comm.RecordTypes;
|
import info.nightscout.androidaps.plugins.pump.danaR.comm.RecordTypes;
|
||||||
import info.nightscout.androidaps.plugins.treatments.Treatment;
|
import info.nightscout.androidaps.plugins.treatments.Treatment;
|
||||||
import info.nightscout.androidaps.utils.DateUtil;
|
import info.nightscout.androidaps.utils.DateUtil;
|
||||||
|
import info.nightscout.androidaps.utils.FabricPrivacy;
|
||||||
import info.nightscout.androidaps.utils.ToastUtils;
|
import info.nightscout.androidaps.utils.ToastUtils;
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||||
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by mike on 28.01.2018.
|
* Created by mike on 28.01.2018.
|
||||||
|
@ -57,6 +62,9 @@ public abstract class AbstractDanaRExecutionService extends DaggerService {
|
||||||
@Inject Context context;
|
@Inject Context context;
|
||||||
@Inject ResourceHelper resourceHelper;
|
@Inject ResourceHelper resourceHelper;
|
||||||
@Inject DanaRPump danaRPump;
|
@Inject DanaRPump danaRPump;
|
||||||
|
@Inject FabricPrivacy fabricPrivacy;
|
||||||
|
|
||||||
|
private CompositeDisposable disposable = new CompositeDisposable();
|
||||||
|
|
||||||
protected String mDevName;
|
protected String mDevName;
|
||||||
|
|
||||||
|
@ -101,22 +109,41 @@ public abstract class AbstractDanaRExecutionService extends DaggerService {
|
||||||
|
|
||||||
public abstract PumpEnactResult setUserOptions();
|
public abstract PumpEnactResult setUserOptions();
|
||||||
|
|
||||||
protected BroadcastReceiver receiver = new BroadcastReceiver() {
|
@Override public void onCreate() {
|
||||||
@Override
|
super.onCreate();
|
||||||
public void onReceive(Context context, Intent intent) {
|
disposable.add(rxBus
|
||||||
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
.toObservable(EventBTChange.class)
|
||||||
String action = intent.getAction();
|
.observeOn(Schedulers.io())
|
||||||
if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
|
.subscribe(event -> {
|
||||||
aapsLogger.debug(LTag.PUMP, "Device was disconnected " + device.getName());//Device was disconnected
|
if (event.getState() == EventBTChange.Change.DISCONNECT) {
|
||||||
if (mBTDevice != null && mBTDevice.getName() != null && mBTDevice.getName().equals(device.getName())) {
|
aapsLogger.debug(LTag.PUMP, "Device was disconnected " + event.getDeviceName());//Device was disconnected
|
||||||
if (mSerialIOThread != null) {
|
if (mBTDevice != null && mBTDevice.getName() != null && mBTDevice.getName().equals(event.getDeviceName())) {
|
||||||
mSerialIOThread.disconnect("BT disconnection broadcast");
|
if (mSerialIOThread != null) {
|
||||||
|
mSerialIOThread.disconnect("BT disconnection broadcast");
|
||||||
|
}
|
||||||
|
rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rxBus.send(new EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED));
|
}, fabricPrivacy::logException)
|
||||||
}
|
);
|
||||||
}
|
disposable.add(rxBus
|
||||||
}
|
.toObservable(EventAppExit.class)
|
||||||
};
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe(event -> {
|
||||||
|
aapsLogger.debug(LTag.PUMP, "EventAppExit received");
|
||||||
|
if (mSerialIOThread != null)
|
||||||
|
mSerialIOThread.disconnect("Application exit");
|
||||||
|
stopSelf();
|
||||||
|
}, fabricPrivacy::logException)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
disposable.clear();
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBinder onBind(Intent intent) {
|
public IBinder onBind(Intent intent) {
|
||||||
|
|
|
@ -92,42 +92,13 @@ public class DanaRExecutionService extends AbstractDanaRExecutionService {
|
||||||
@Inject ProfileFunction profileFunction;
|
@Inject ProfileFunction profileFunction;
|
||||||
@Inject SP sp;
|
@Inject SP sp;
|
||||||
|
|
||||||
private CompositeDisposable disposable = new CompositeDisposable();
|
|
||||||
|
|
||||||
public DanaRExecutionService() {
|
public DanaRExecutionService() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
mBinder = new LocalBinder();
|
mBinder = new LocalBinder();
|
||||||
context.registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED));
|
|
||||||
disposable.add(rxBus
|
|
||||||
.toObservable(EventPreferenceChange.class)
|
|
||||||
.observeOn(Schedulers.io())
|
|
||||||
.subscribe(event -> {
|
|
||||||
if (mSerialIOThread != null)
|
|
||||||
mSerialIOThread.disconnect("EventPreferenceChange");
|
|
||||||
}, exception -> FabricPrivacy.getInstance().logException(exception))
|
|
||||||
);
|
|
||||||
disposable.add(rxBus
|
|
||||||
.toObservable(EventAppExit.class)
|
|
||||||
.observeOn(Schedulers.io())
|
|
||||||
.subscribe(event -> {
|
|
||||||
aapsLogger.debug(LTag.PUMP, "EventAppExit received");
|
|
||||||
if (mSerialIOThread != null)
|
|
||||||
mSerialIOThread.disconnect("Application exit");
|
|
||||||
context.unregisterReceiver(receiver);
|
|
||||||
stopSelf();
|
|
||||||
}, exception -> FabricPrivacy.getInstance().logException(exception))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
disposable.clear();
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LocalBinder extends Binder {
|
public class LocalBinder extends Binder {
|
||||||
|
|
|
@ -83,8 +83,6 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
|
||||||
@Inject ActivePluginProvider activePlugin;
|
@Inject ActivePluginProvider activePlugin;
|
||||||
@Inject ProfileFunction profileFunction;
|
@Inject ProfileFunction profileFunction;
|
||||||
|
|
||||||
private CompositeDisposable disposable = new CompositeDisposable();
|
|
||||||
|
|
||||||
public DanaRKoreanExecutionService() {
|
public DanaRKoreanExecutionService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,33 +90,6 @@ public class DanaRKoreanExecutionService extends AbstractDanaRExecutionService {
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
mBinder = new LocalBinder();
|
mBinder = new LocalBinder();
|
||||||
context.registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED));
|
|
||||||
disposable.add(rxBus
|
|
||||||
.toObservable(EventPreferenceChange.class)
|
|
||||||
.observeOn(Schedulers.io())
|
|
||||||
.subscribe(event -> {
|
|
||||||
if (mSerialIOThread != null)
|
|
||||||
mSerialIOThread.disconnect("EventPreferenceChange");
|
|
||||||
}, exception -> FabricPrivacy.getInstance().logException(exception))
|
|
||||||
);
|
|
||||||
disposable.add(rxBus
|
|
||||||
.toObservable(EventAppExit.class)
|
|
||||||
.observeOn(Schedulers.io())
|
|
||||||
.subscribe(event -> {
|
|
||||||
aapsLogger.debug(LTag.PUMP, "EventAppExit received");
|
|
||||||
|
|
||||||
if (mSerialIOThread != null)
|
|
||||||
mSerialIOThread.disconnect("Application exit");
|
|
||||||
context.unregisterReceiver(receiver);
|
|
||||||
stopSelf();
|
|
||||||
}, exception -> FabricPrivacy.getInstance().logException(exception))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
disposable.clear();
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LocalBinder extends Binder {
|
public class LocalBinder extends Binder {
|
||||||
|
|
|
@ -108,8 +108,6 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
|
||||||
@Inject ProfileFunction profileFunction;
|
@Inject ProfileFunction profileFunction;
|
||||||
@Inject SP sp;
|
@Inject SP sp;
|
||||||
|
|
||||||
private CompositeDisposable disposable = new CompositeDisposable();
|
|
||||||
|
|
||||||
private long lastHistoryFetched = 0;
|
private long lastHistoryFetched = 0;
|
||||||
|
|
||||||
public DanaRv2ExecutionService() {
|
public DanaRv2ExecutionService() {
|
||||||
|
@ -125,33 +123,6 @@ public class DanaRv2ExecutionService extends AbstractDanaRExecutionService {
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
mBinder = new LocalBinder();
|
mBinder = new LocalBinder();
|
||||||
context.registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED));
|
|
||||||
disposable.add(rxBus
|
|
||||||
.toObservable(EventPreferenceChange.class)
|
|
||||||
.observeOn(Schedulers.io())
|
|
||||||
.subscribe(event -> {
|
|
||||||
if (mSerialIOThread != null)
|
|
||||||
mSerialIOThread.disconnect("EventPreferenceChange");
|
|
||||||
}, exception -> FabricPrivacy.getInstance().logException(exception))
|
|
||||||
);
|
|
||||||
disposable.add(rxBus
|
|
||||||
.toObservable(EventAppExit.class)
|
|
||||||
.observeOn(Schedulers.io())
|
|
||||||
.subscribe(event -> {
|
|
||||||
aapsLogger.debug(LTag.PUMP, "EventAppExit received");
|
|
||||||
|
|
||||||
if (mSerialIOThread != null)
|
|
||||||
mSerialIOThread.disconnect("Application exit");
|
|
||||||
context.getApplicationContext().unregisterReceiver(receiver);
|
|
||||||
stopSelf();
|
|
||||||
}, exception -> FabricPrivacy.getInstance().logException(exception))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
disposable.clear();
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect() {
|
public void connect() {
|
||||||
|
|
|
@ -37,6 +37,7 @@ import info.nightscout.androidaps.queue.Callback
|
||||||
import info.nightscout.androidaps.queue.events.EventQueueChanged
|
import info.nightscout.androidaps.queue.events.EventQueueChanged
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
|
import info.nightscout.androidaps.utils.OKDialog
|
||||||
import info.nightscout.androidaps.utils.SetWarnColor
|
import info.nightscout.androidaps.utils.SetWarnColor
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||||
|
@ -86,13 +87,13 @@ class MedtronicFragment : DaggerFragment() {
|
||||||
if (MedtronicUtil.getPumpStatus().verifyConfiguration()) {
|
if (MedtronicUtil.getPumpStatus().verifyConfiguration()) {
|
||||||
startActivity(Intent(context, MedtronicHistoryActivity::class.java))
|
startActivity(Intent(context, MedtronicHistoryActivity::class.java))
|
||||||
} else {
|
} else {
|
||||||
MedtronicUtil.displayNotConfiguredDialog(context)
|
displayNotConfiguredDialog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
medtronic_refresh.setOnClickListener {
|
medtronic_refresh.setOnClickListener {
|
||||||
if (!MedtronicUtil.getPumpStatus().verifyConfiguration()) {
|
if (!MedtronicUtil.getPumpStatus().verifyConfiguration()) {
|
||||||
MedtronicUtil.displayNotConfiguredDialog(context)
|
displayNotConfiguredDialog()
|
||||||
} else {
|
} else {
|
||||||
medtronic_refresh.isEnabled = false
|
medtronic_refresh.isEnabled = false
|
||||||
medtronicPumpPlugin.resetStatusState()
|
medtronicPumpPlugin.resetStatusState()
|
||||||
|
@ -108,7 +109,7 @@ class MedtronicFragment : DaggerFragment() {
|
||||||
if (MedtronicUtil.getPumpStatus().verifyConfiguration()) {
|
if (MedtronicUtil.getPumpStatus().verifyConfiguration()) {
|
||||||
startActivity(Intent(context, RileyLinkStatusActivity::class.java))
|
startActivity(Intent(context, RileyLinkStatusActivity::class.java))
|
||||||
} else {
|
} else {
|
||||||
MedtronicUtil.displayNotConfiguredDialog(context)
|
displayNotConfiguredDialog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -247,6 +248,13 @@ class MedtronicFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun displayNotConfiguredDialog() {
|
||||||
|
context?.let {
|
||||||
|
OKDialog.show(it, resourceHelper.gs(R.string.combo_warning),
|
||||||
|
resourceHelper.gs(R.string.medtronic_error_operation_not_possible_no_configuration), null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GUI functions
|
// GUI functions
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun updateGUI() {
|
fun updateGUI() {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.medtronic.comm.ui;
|
package info.nightscout.androidaps.plugins.pump.medtronic.comm.ui;
|
||||||
|
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||||
import info.nightscout.androidaps.logging.L;
|
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
import info.nightscout.androidaps.logging.LTag;
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||||
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst;
|
import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst;
|
||||||
|
@ -43,8 +42,7 @@ public class MedtronicUIComm {
|
||||||
|
|
||||||
public synchronized MedtronicUITask executeCommand(MedtronicCommandType commandType, Object... parameters) {
|
public synchronized MedtronicUITask executeCommand(MedtronicCommandType commandType, Object... parameters) {
|
||||||
|
|
||||||
if (isLogEnabled())
|
aapsLogger.warn(LTag.PUMP, "Execute Command: " + commandType.name());
|
||||||
aapsLogger.warn(LTag.PUMP, "Execute Command: " + commandType.name());
|
|
||||||
|
|
||||||
MedtronicUITask task = new MedtronicUITask(commandType, parameters);
|
MedtronicUITask task = new MedtronicUITask(commandType, parameters);
|
||||||
|
|
||||||
|
@ -78,7 +76,7 @@ public class MedtronicUIComm {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (!task.isReceived() && isLogEnabled()) {
|
if (!task.isReceived()) {
|
||||||
aapsLogger.warn(LTag.PUMP, "Reply not received for " + commandType);
|
aapsLogger.warn(LTag.PUMP, "Reply not received for " + commandType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,9 +110,4 @@ public class MedtronicUIComm {
|
||||||
public void startTunning() {
|
public void startTunning() {
|
||||||
RileyLinkUtil.sendBroadcastMessage(RileyLinkConst.IPC.MSG_PUMP_tunePump);
|
RileyLinkUtil.sendBroadcastMessage(RileyLinkConst.IPC.MSG_PUMP_tunePump);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isLogEnabled() {
|
|
||||||
return L.isEnabled(L.PUMP);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,11 +64,6 @@ public class RileyLinkMedtronicService extends RileyLinkService {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static MedtronicCommunicationManager getCommunicationManager() {
|
|
||||||
return instance.medtronicCommunicationManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConfigurationChanged(Configuration newConfig) {
|
public void onConfigurationChanged(Configuration newConfig) {
|
||||||
aapsLogger.warn(LTag.PUMPCOMM, "onConfigurationChanged");
|
aapsLogger.warn(LTag.PUMPCOMM, "onConfigurationChanged");
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.medtronic.util;
|
package info.nightscout.androidaps.plugins.pump.medtronic.util;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
|
|
||||||
import org.joda.time.LocalTime;
|
import org.joda.time.LocalTime;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
@ -15,8 +12,6 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import info.nightscout.androidaps.MainApp;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginType;
|
import info.nightscout.androidaps.interfaces.PluginType;
|
||||||
import info.nightscout.androidaps.logging.L;
|
import info.nightscout.androidaps.logging.L;
|
||||||
import info.nightscout.androidaps.logging.StacktraceLoggerWrapper;
|
import info.nightscout.androidaps.logging.StacktraceLoggerWrapper;
|
||||||
|
@ -41,7 +36,6 @@ import info.nightscout.androidaps.plugins.pump.medtronic.defs.PumpDeviceState;
|
||||||
import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus;
|
import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus;
|
||||||
import info.nightscout.androidaps.plugins.pump.medtronic.events.EventMedtronicDeviceStatusChange;
|
import info.nightscout.androidaps.plugins.pump.medtronic.events.EventMedtronicDeviceStatusChange;
|
||||||
import info.nightscout.androidaps.plugins.pump.medtronic.service.RileyLinkMedtronicService;
|
import info.nightscout.androidaps.plugins.pump.medtronic.service.RileyLinkMedtronicService;
|
||||||
import info.nightscout.androidaps.utils.OKDialog;
|
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -532,9 +526,4 @@ public class MedtronicUtil extends RileyLinkUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void displayNotConfiguredDialog(Context context) {
|
|
||||||
OKDialog.show(context, MainApp.gs(R.string.combo_warning),
|
|
||||||
MainApp.gs(R.string.medtronic_error_operation_not_possible_no_configuration), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification;
|
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification;
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensResult;
|
||||||
|
import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin;
|
||||||
import info.nightscout.androidaps.plugins.pump.medtronic.data.MedtronicHistoryData;
|
import info.nightscout.androidaps.plugins.pump.medtronic.data.MedtronicHistoryData;
|
||||||
import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil;
|
import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil;
|
||||||
import info.nightscout.androidaps.utils.DateUtil;
|
import info.nightscout.androidaps.utils.DateUtil;
|
||||||
|
@ -571,7 +572,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
|
||||||
// return true if new record is created
|
// return true if new record is created
|
||||||
@Override
|
@Override
|
||||||
public boolean addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo, boolean allowUpdate) {
|
public boolean addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo, boolean allowUpdate) {
|
||||||
boolean medtronicPump = MedtronicUtil.isMedtronicPump();
|
boolean medtronicPump = activePlugin.getActivePump() instanceof MedtronicPumpPlugin;
|
||||||
|
|
||||||
getAapsLogger().debug(MedtronicHistoryData.doubleBolusDebug, LTag.DATATREATMENTS, "DoubleBolusDebug: addToHistoryTreatment::isMedtronicPump={} " + medtronicPump);
|
getAapsLogger().debug(MedtronicHistoryData.doubleBolusDebug, LTag.DATATREATMENTS, "DoubleBolusDebug: addToHistoryTreatment::isMedtronicPump={} " + medtronicPump);
|
||||||
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
package info.nightscout.androidaps.receivers;
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.plugins.general.persistentNotification.DummyService;
|
|
||||||
|
|
||||||
public class AutoStartReceiver extends BroadcastReceiver {
|
|
||||||
public AutoStartReceiver() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
|
||||||
context.startForegroundService(new Intent(context, DummyService.class));
|
|
||||||
else
|
|
||||||
context.startService(new Intent(context, DummyService.class));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package info.nightscout.androidaps.receivers
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import info.nightscout.androidaps.plugins.general.persistentNotification.DummyService
|
||||||
|
|
||||||
|
class AutoStartReceiver : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||||
|
context.startForegroundService(Intent(context, DummyService::class.java))
|
||||||
|
else
|
||||||
|
context.startService(Intent(context, DummyService::class.java))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package info.nightscout.androidaps.receivers
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothDevice
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import dagger.android.DaggerBroadcastReceiver
|
||||||
|
import info.nightscout.androidaps.events.EventBTChange
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class BTReceiver : DaggerBroadcastReceiver() {
|
||||||
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
|
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
super.onReceive(context, intent)
|
||||||
|
val device : BluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
|
||||||
|
|
||||||
|
when (intent.action) {
|
||||||
|
BluetoothDevice.ACTION_ACL_CONNECTED ->
|
||||||
|
rxBus.send(EventBTChange(EventBTChange.Change.CONNECT, device.name))
|
||||||
|
BluetoothDevice.ACTION_ACL_DISCONNECTED ->
|
||||||
|
rxBus.send(EventBTChange(EventBTChange.Change.DISCONNECT, device.name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,45 +0,0 @@
|
||||||
package info.nightscout.androidaps.receivers;
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.BatteryManager;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.events.EventChargingState;
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
|
||||||
|
|
||||||
public class ChargingStateReceiver extends BroadcastReceiver {
|
|
||||||
|
|
||||||
private static EventChargingState lastEvent;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
EventChargingState event = grabChargingState(context);
|
|
||||||
|
|
||||||
if (event != null)
|
|
||||||
RxBus.Companion.getINSTANCE().send(event);
|
|
||||||
lastEvent = event;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EventChargingState grabChargingState(Context context) {
|
|
||||||
BatteryManager bm = (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE);
|
|
||||||
|
|
||||||
if (bm == null)
|
|
||||||
return new EventChargingState(false);
|
|
||||||
|
|
||||||
int status = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS);
|
|
||||||
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING
|
|
||||||
|| status == BatteryManager.BATTERY_STATUS_FULL;
|
|
||||||
|
|
||||||
EventChargingState event = new EventChargingState(isCharging);
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
static public boolean isCharging() {
|
|
||||||
return lastEvent != null && lastEvent.isCharging();
|
|
||||||
}
|
|
||||||
|
|
||||||
static public EventChargingState getLastEvent() {
|
|
||||||
return lastEvent;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package info.nightscout.androidaps.receivers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.os.BatteryManager
|
||||||
|
import dagger.android.DaggerBroadcastReceiver
|
||||||
|
import info.nightscout.androidaps.events.EventChargingState
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class ChargingStateReceiver : DaggerBroadcastReceiver() {
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
|
@Inject lateinit var receiverStatusStore: ReceiverStatusStore
|
||||||
|
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
super.onReceive(context, intent)
|
||||||
|
rxBus.send(grabChargingState(context))
|
||||||
|
aapsLogger.debug(LTag.CORE, receiverStatusStore.lastChargingEvent!!.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun grabChargingState(context: Context): EventChargingState {
|
||||||
|
val batteryStatus: Intent? = IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { iFilter ->
|
||||||
|
context.registerReceiver(null, iFilter)
|
||||||
|
}
|
||||||
|
val status: Int = batteryStatus?.getIntExtra(BatteryManager.EXTRA_STATUS, -1) ?: -1
|
||||||
|
val isCharging: Boolean = status == BatteryManager.BATTERY_STATUS_CHARGING
|
||||||
|
|| status == BatteryManager.BATTERY_STATUS_FULL
|
||||||
|
return EventChargingState(isCharging).also { receiverStatusStore.lastChargingEvent = it }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,25 +0,0 @@
|
||||||
package info.nightscout.androidaps.receivers;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import androidx.legacy.content.WakefulBroadcastReceiver;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.logging.L;
|
|
||||||
import info.nightscout.androidaps.logging.StacktraceLoggerWrapper;
|
|
||||||
import info.nightscout.androidaps.services.DataService;
|
|
||||||
|
|
||||||
public class DataReceiver extends WakefulBroadcastReceiver {
|
|
||||||
private static Logger log = StacktraceLoggerWrapper.getLogger(L.DATASERVICE);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
if (L.isEnabled(L.DATASERVICE))
|
|
||||||
log.debug("onReceive " + intent);
|
|
||||||
startWakefulService(context, new Intent(context, DataService.class)
|
|
||||||
.setAction(intent.getAction())
|
|
||||||
.putExtras(intent));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package info.nightscout.androidaps.receivers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.legacy.content.*
|
||||||
|
import dagger.android.AndroidInjection
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.services.DataService
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
// We are not ready to switch to JobScheduler
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
open class DataReceiver : WakefulBroadcastReceiver() {
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
AndroidInjection.inject(this, context)
|
||||||
|
aapsLogger.debug(LTag.DATASERVICE, "onReceive $intent")
|
||||||
|
startWakefulService(context, Intent(context, DataService::class.java)
|
||||||
|
.setAction(intent.action)
|
||||||
|
.putExtras(intent))
|
||||||
|
}
|
||||||
|
}
|
|
@ -98,13 +98,12 @@ class KeepAliveReceiver : DaggerBroadcastReceiver() {
|
||||||
// if there is no BG available, we have to upload anyway to have correct
|
// if there is no BG available, we have to upload anyway to have correct
|
||||||
// IOB displayed in NS
|
// IOB displayed in NS
|
||||||
private fun checkAPS() {
|
private fun checkAPS() {
|
||||||
val usedAPS = activePlugin.activeAPS
|
|
||||||
var shouldUploadStatus = false
|
var shouldUploadStatus = false
|
||||||
if (Config.NSCLIENT) return
|
if (Config.NSCLIENT) return
|
||||||
if (Config.PUMPCONTROL) shouldUploadStatus = true
|
if (Config.PUMPCONTROL) shouldUploadStatus = true
|
||||||
if (!loopPlugin.isEnabled() || iobCobCalculatorPlugin.actualBg() == null)
|
else if (!loopPlugin.isEnabled() || iobCobCalculatorPlugin.actualBg() == null)
|
||||||
shouldUploadStatus = true
|
shouldUploadStatus = true
|
||||||
else if (DateUtil.isOlderThan(usedAPS.lastAPSRun, 5)) shouldUploadStatus = true
|
else if (DateUtil.isOlderThan(activePlugin.activeAPS.lastAPSRun, 5)) shouldUploadStatus = true
|
||||||
if (DateUtil.isOlderThan(lastIobUpload, IOB_UPDATE_FREQUENCY) && shouldUploadStatus) {
|
if (DateUtil.isOlderThan(lastIobUpload, IOB_UPDATE_FREQUENCY) && shouldUploadStatus) {
|
||||||
lastIobUpload = DateUtil.now()
|
lastIobUpload = DateUtil.now()
|
||||||
NSUpload.uploadDeviceStatus(loopPlugin, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump)
|
NSUpload.uploadDeviceStatus(loopPlugin, iobCobCalculatorPlugin, profileFunction, activePlugin.activePump)
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
package info.nightscout.androidaps.receivers;
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.NetworkInfo;
|
|
||||||
import android.net.wifi.SupplicantState;
|
|
||||||
import android.net.wifi.WifiInfo;
|
|
||||||
import android.net.wifi.WifiManager;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.MainApp;
|
|
||||||
import info.nightscout.androidaps.events.EventNetworkChange;
|
|
||||||
import info.nightscout.androidaps.logging.L;
|
|
||||||
import info.nightscout.androidaps.logging.StacktraceLoggerWrapper;
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
|
||||||
|
|
||||||
public class NetworkChangeReceiver extends BroadcastReceiver {
|
|
||||||
|
|
||||||
private static Logger log = StacktraceLoggerWrapper.getLogger(L.CORE);
|
|
||||||
|
|
||||||
private static EventNetworkChange lastEvent = null;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
|
||||||
EventNetworkChange event = grabNetworkStatus(context);
|
|
||||||
if (event != null)
|
|
||||||
RxBus.Companion.getINSTANCE().send(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static EventNetworkChange grabNetworkStatus(final Context context) {
|
|
||||||
EventNetworkChange event = new EventNetworkChange();
|
|
||||||
|
|
||||||
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
||||||
if (cm == null) return null;
|
|
||||||
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
|
|
||||||
|
|
||||||
if (activeNetwork != null) {
|
|
||||||
if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI && activeNetwork.isConnected()) {
|
|
||||||
event.setWifiConnected(true);
|
|
||||||
WifiManager wifiManager = (WifiManager) MainApp.instance().getApplicationContext().getSystemService(Context.WIFI_SERVICE);
|
|
||||||
if (wifiManager != null) {
|
|
||||||
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
|
|
||||||
if (wifiInfo.getSupplicantState() == SupplicantState.COMPLETED) {
|
|
||||||
event.setSsid(wifiInfo.getSSID());
|
|
||||||
}
|
|
||||||
if (L.isEnabled(L.CORE))
|
|
||||||
log.debug("NETCHANGE: Wifi connected. SSID: " + event.connectedSsid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
|
|
||||||
event.setMobileConnected(true);
|
|
||||||
event.setRoaming(activeNetwork.isRoaming());
|
|
||||||
if (L.isEnabled(L.CORE))
|
|
||||||
log.debug("NETCHANGE: Mobile connected. Roaming: " + event.getRoaming());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (L.isEnabled(L.CORE))
|
|
||||||
log.debug("NETCHANGE: Disconnected.");
|
|
||||||
}
|
|
||||||
|
|
||||||
lastEvent = event;
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isWifiConnected() {
|
|
||||||
return lastEvent != null && lastEvent.getWifiConnected();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isConnected() {
|
|
||||||
return lastEvent != null && (lastEvent.getWifiConnected() || lastEvent.getMobileConnected());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EventNetworkChange getLastEvent() {
|
|
||||||
return lastEvent;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
package info.nightscout.androidaps.receivers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.Network
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
|
import android.net.wifi.SupplicantState
|
||||||
|
import android.net.wifi.WifiManager
|
||||||
|
import dagger.android.DaggerBroadcastReceiver
|
||||||
|
import info.nightscout.androidaps.events.EventNetworkChange
|
||||||
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class NetworkChangeReceiver : DaggerBroadcastReceiver() {
|
||||||
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
|
@Inject lateinit var receiverStatusStore: ReceiverStatusStore
|
||||||
|
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
super.onReceive(context, intent)
|
||||||
|
rxBus.send(grabNetworkStatus(context, aapsLogger))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun grabNetworkStatus(context: Context, aapsLogger: AAPSLogger): EventNetworkChange {
|
||||||
|
val event = EventNetworkChange()
|
||||||
|
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
|
val networks: Array<Network> = cm.allNetworks
|
||||||
|
networks.forEach {
|
||||||
|
val capabilities = cm.getNetworkCapabilities(it)
|
||||||
|
event.wifiConnected = event.wifiConnected || (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
|
||||||
|
|| capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET))
|
||||||
|
event.mobileConnected = event.mobileConnected || capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||||
|
event.vpnConnected = event.vpnConnected || capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)
|
||||||
|
// if (event.vpnConnected) aapsLogger.debug(LTag.CORE, "NETCHANGE: VPN connected.")
|
||||||
|
if (event.wifiConnected) {
|
||||||
|
val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||||
|
val wifiInfo = wifiManager.connectionInfo
|
||||||
|
if (wifiInfo.supplicantState == SupplicantState.COMPLETED) {
|
||||||
|
event.ssid = wifiInfo.ssid
|
||||||
|
// aapsLogger.debug(LTag.CORE, "NETCHANGE: Wifi connected. SSID: ${event.connectedSsid()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (event.mobileConnected) {
|
||||||
|
event.mobileConnected = true
|
||||||
|
event.roaming = event.roaming || !capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
|
||||||
|
event.metered = event.metered || !capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
|
||||||
|
aapsLogger.debug(LTag.CORE, "NETCHANGE: Mobile connected. Roaming: ${event.roaming} Metered: ${event.metered}")
|
||||||
|
}
|
||||||
|
// aapsLogger.info(LTag.CORE, "Network: $it")
|
||||||
|
}
|
||||||
|
|
||||||
|
aapsLogger.debug(LTag.CORE, event.toString())
|
||||||
|
receiverStatusStore.lastNetworkEvent = event
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package info.nightscout.androidaps.receivers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import info.nightscout.androidaps.events.EventChargingState
|
||||||
|
import info.nightscout.androidaps.events.EventNetworkChange
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class ReceiverStatusStore @Inject constructor(val context: Context, val rxBus: RxBusWrapper) {
|
||||||
|
|
||||||
|
var lastNetworkEvent: EventNetworkChange? = null
|
||||||
|
|
||||||
|
val isWifiConnected: Boolean
|
||||||
|
get() = lastNetworkEvent?.wifiConnected ?: false
|
||||||
|
|
||||||
|
val isConnected: Boolean
|
||||||
|
get() = lastNetworkEvent?.wifiConnected ?: false || lastNetworkEvent?.mobileConnected ?: false
|
||||||
|
|
||||||
|
fun updateNetworkStatus() {
|
||||||
|
context.sendBroadcast(Intent(context, NetworkChangeReceiver::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastChargingEvent: EventChargingState? = null
|
||||||
|
|
||||||
|
val isCharging: Boolean
|
||||||
|
get() = lastChargingEvent?.isCharging ?: false
|
||||||
|
|
||||||
|
fun broadcastChargingState() {
|
||||||
|
lastChargingEvent?.let { rxBus.send(it) }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
package info.nightscout.androidaps.receivers;
|
package info.nightscout.androidaps.receivers
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forward received SMS intents. This is a separate class, because unlike local broadcasts handled by DataReceiver,
|
* Forward received SMS intents. This is a separate class, because unlike local broadcasts handled by DataReceiver,
|
||||||
* receiving SMS requires a special permission in the manifest, which necessitates a separate receiver.
|
* receiving SMS requires a special permission in the manifest, which necessitates a separate receiver.
|
||||||
*/
|
*/
|
||||||
public class SmsReceiver extends DataReceiver {}
|
class SmsReceiver : DataReceiver()
|
|
@ -1,9 +1,7 @@
|
||||||
package info.nightscout.androidaps.receivers
|
package info.nightscout.androidaps.receivers
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
|
||||||
import dagger.android.DaggerBroadcastReceiver
|
import dagger.android.DaggerBroadcastReceiver
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||||
import info.nightscout.androidaps.interfaces.PumpInterface
|
import info.nightscout.androidaps.interfaces.PumpInterface
|
||||||
|
@ -18,19 +16,11 @@ class TimeDateOrTZChangeReceiver : DaggerBroadcastReceiver() {
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
super.onReceive(context, intent)
|
super.onReceive(context, intent)
|
||||||
val action = intent.action
|
val action = intent.action
|
||||||
val activePump: PumpInterface = activePlugin.getActivePump()
|
val activePump: PumpInterface = activePlugin.activePump
|
||||||
aapsLogger.debug(LTag.PUMP, "Date, Time and/or TimeZone changed.")
|
aapsLogger.debug(LTag.PUMP, "Date, Time and/or TimeZone changed.")
|
||||||
if (action != null) {
|
if (action != null) {
|
||||||
aapsLogger.debug(LTag.PUMP, "Date, Time and/or TimeZone changed. Notifying pump driver.")
|
aapsLogger.debug(LTag.PUMP, "Date, Time and/or TimeZone changed. Notifying pump driver.")
|
||||||
activePump.timeDateOrTimeZoneChanged()
|
activePump.timeDateOrTimeZoneChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun registerBroadcasts(context: Context) {
|
|
||||||
val filter = IntentFilter()
|
|
||||||
filter.addAction(Intent.ACTION_TIME_CHANGED)
|
|
||||||
filter.addAction(Intent.ACTION_DATE_CHANGED)
|
|
||||||
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED)
|
|
||||||
context.registerReceiver(this, filter)
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
package info.nightscout.androidaps.setupwizard
|
package info.nightscout.androidaps.setupwizard
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.Config
|
import info.nightscout.androidaps.Config
|
||||||
import info.nightscout.androidaps.Constants
|
import info.nightscout.androidaps.Constants
|
||||||
import info.nightscout.androidaps.MainApp
|
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.activities.PreferencesActivity
|
import info.nightscout.androidaps.activities.PreferencesActivity
|
||||||
import info.nightscout.androidaps.dialogs.ProfileSwitchDialog
|
import info.nightscout.androidaps.dialogs.ProfileSwitchDialog
|
||||||
|
@ -46,7 +46,7 @@ import javax.inject.Singleton
|
||||||
class SWDefinition @Inject constructor(
|
class SWDefinition @Inject constructor(
|
||||||
injector: HasAndroidInjector,
|
injector: HasAndroidInjector,
|
||||||
private val rxBus: RxBusWrapper,
|
private val rxBus: RxBusWrapper,
|
||||||
private val mainApp: MainApp,
|
private val context: Context,
|
||||||
resourceHelper: ResourceHelper,
|
resourceHelper: ResourceHelper,
|
||||||
private val sp: SP,
|
private val sp: SP,
|
||||||
private val profileFunction: ProfileFunction,
|
private val profileFunction: ProfileFunction,
|
||||||
|
@ -58,10 +58,12 @@ class SWDefinition @Inject constructor(
|
||||||
private val loopPlugin: LoopPlugin,
|
private val loopPlugin: LoopPlugin,
|
||||||
private val nsClientPlugin: NSClientPlugin,
|
private val nsClientPlugin: NSClientPlugin,
|
||||||
private val nsProfilePlugin: NSProfilePlugin,
|
private val nsProfilePlugin: NSProfilePlugin,
|
||||||
private val protectionCheck: ProtectionCheck
|
private val protectionCheck: ProtectionCheck,
|
||||||
|
private val importExportPrefs: ImportExportPrefs,
|
||||||
|
private val androidPermission: AndroidPermission
|
||||||
) {
|
) {
|
||||||
|
|
||||||
var activity: AppCompatActivity? = null
|
lateinit var activity: AppCompatActivity
|
||||||
private val screens: MutableList<SWScreen> = ArrayList()
|
private val screens: MutableList<SWScreen> = ArrayList()
|
||||||
|
|
||||||
fun getScreens(): List<SWScreen> {
|
fun getScreens(): List<SWScreen> {
|
||||||
|
@ -83,7 +85,7 @@ class SWDefinition @Inject constructor(
|
||||||
.preferenceId(R.string.key_language).label(R.string.language)
|
.preferenceId(R.string.key_language).label(R.string.language)
|
||||||
.comment(R.string.setupwizard_language_prompt))
|
.comment(R.string.setupwizard_language_prompt))
|
||||||
.validator(SWValidator {
|
.validator(SWValidator {
|
||||||
update(mainApp)
|
update(context)
|
||||||
sp.contains(R.string.key_language)
|
sp.contains(R.string.key_language)
|
||||||
})
|
})
|
||||||
private val screenEula = SWScreen(injector, R.string.end_user_license_agreement)
|
private val screenEula = SWScreen(injector, R.string.end_user_license_agreement)
|
||||||
|
@ -127,10 +129,10 @@ class SWDefinition @Inject constructor(
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWButton(injector)
|
.add(SWButton(injector)
|
||||||
.text(R.string.askforpermission)
|
.text(R.string.askforpermission)
|
||||||
.visibility(SWValidator { AndroidPermission.permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) })
|
.visibility(SWValidator { androidPermission.permissionNotGranted(context, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) })
|
||||||
.action(Runnable { AndroidPermission.askForPermission(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, AndroidPermission.CASE_BATTERY) }))
|
.action(Runnable { androidPermission.askForPermission(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, AndroidPermission.CASE_BATTERY) }))
|
||||||
.visibility(SWValidator { AndroidPermission.permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) })
|
.visibility(SWValidator { androidPermission.permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) })
|
||||||
.validator(SWValidator { !AndroidPermission.permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) })
|
.validator(SWValidator { !androidPermission.permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) })
|
||||||
private val screenPermissionBt = SWScreen(injector, R.string.permission)
|
private val screenPermissionBt = SWScreen(injector, R.string.permission)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfotext(injector)
|
||||||
|
@ -138,10 +140,10 @@ class SWDefinition @Inject constructor(
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWButton(injector)
|
.add(SWButton(injector)
|
||||||
.text(R.string.askforpermission)
|
.text(R.string.askforpermission)
|
||||||
.visibility(SWValidator { AndroidPermission.permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION) })
|
.visibility(SWValidator { androidPermission.permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION) })
|
||||||
.action(Runnable { AndroidPermission.askForPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION, AndroidPermission.CASE_LOCATION) }))
|
.action(Runnable { androidPermission.askForPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION, AndroidPermission.CASE_LOCATION) }))
|
||||||
.visibility(SWValidator { AndroidPermission.permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION) })
|
.visibility(SWValidator { androidPermission.permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION) })
|
||||||
.validator(SWValidator { !AndroidPermission.permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION) })
|
.validator(SWValidator { !androidPermission.permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION) })
|
||||||
private val screenPermissionStore = SWScreen(injector, R.string.permission)
|
private val screenPermissionStore = SWScreen(injector, R.string.permission)
|
||||||
.skippable(false)
|
.skippable(false)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfotext(injector)
|
||||||
|
@ -149,18 +151,18 @@ class SWDefinition @Inject constructor(
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWButton(injector)
|
.add(SWButton(injector)
|
||||||
.text(R.string.askforpermission)
|
.text(R.string.askforpermission)
|
||||||
.visibility(SWValidator { AndroidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) })
|
.visibility(SWValidator { androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) })
|
||||||
.action(Runnable { AndroidPermission.askForPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE, AndroidPermission.CASE_STORAGE) }))
|
.action(Runnable { androidPermission.askForPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE, AndroidPermission.CASE_STORAGE) }))
|
||||||
.visibility(SWValidator { AndroidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) })
|
.visibility(SWValidator { androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) })
|
||||||
.validator(SWValidator { !AndroidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) })
|
.validator(SWValidator { !androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) })
|
||||||
private val screenImport = SWScreen(injector, R.string.nav_import)
|
private val screenImport = SWScreen(injector, R.string.nav_import)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfotext(injector)
|
||||||
.label(R.string.storedsettingsfound))
|
.label(R.string.storedsettingsfound))
|
||||||
.add(SWBreak(injector))
|
.add(SWBreak(injector))
|
||||||
.add(SWButton(injector)
|
.add(SWButton(injector)
|
||||||
.text(R.string.nav_import)
|
.text(R.string.nav_import)
|
||||||
.action(Runnable { ImportExportPrefs.importSharedPreferences(activity) }))
|
.action(Runnable { importExportPrefs.importSharedPreferences(activity) }))
|
||||||
.visibility(SWValidator { ImportExportPrefs.file.exists() && !AndroidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) })
|
.visibility(SWValidator { importExportPrefs.prefsFileExists() && !androidPermission.permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) })
|
||||||
private val screenNsClient = SWScreen(injector, R.string.nsclientinternal_title)
|
private val screenNsClient = SWScreen(injector, R.string.nsclientinternal_title)
|
||||||
.skippable(true)
|
.skippable(true)
|
||||||
.add(SWInfotext(injector)
|
.add(SWInfotext(injector)
|
||||||
|
@ -219,13 +221,11 @@ class SWDefinition @Inject constructor(
|
||||||
.text(R.string.insulinsourcesetup)
|
.text(R.string.insulinsourcesetup)
|
||||||
.action(Runnable {
|
.action(Runnable {
|
||||||
val plugin = activePlugin.activeInsulin as PluginBase
|
val plugin = activePlugin.activeInsulin as PluginBase
|
||||||
activity?.let { activity ->
|
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable {
|
||||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable {
|
val i = Intent(activity, PreferencesActivity::class.java)
|
||||||
val i = Intent(activity, PreferencesActivity::class.java)
|
i.putExtra("id", plugin.preferencesId)
|
||||||
i.putExtra("id", plugin.preferencesId)
|
activity.startActivity(i)
|
||||||
activity.startActivity(i)
|
}, null)
|
||||||
}, null)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.visibility(SWValidator { (activePlugin.activeInsulin as PluginBase).preferencesId > 0 }))
|
.visibility(SWValidator { (activePlugin.activeInsulin as PluginBase).preferencesId > 0 }))
|
||||||
private val screenBgSource = SWScreen(injector, R.string.configbuilder_bgsource)
|
private val screenBgSource = SWScreen(injector, R.string.configbuilder_bgsource)
|
||||||
|
@ -238,13 +238,11 @@ class SWDefinition @Inject constructor(
|
||||||
.text(R.string.bgsourcesetup)
|
.text(R.string.bgsourcesetup)
|
||||||
.action(Runnable {
|
.action(Runnable {
|
||||||
val plugin = activePlugin.activeBgSource as PluginBase
|
val plugin = activePlugin.activeBgSource as PluginBase
|
||||||
activity?.let { activity ->
|
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable {
|
||||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable {
|
val i = Intent(activity, PreferencesActivity::class.java)
|
||||||
val i = Intent(activity, PreferencesActivity::class.java)
|
i.putExtra("id", plugin.preferencesId)
|
||||||
i.putExtra("id", plugin.preferencesId)
|
activity.startActivity(i)
|
||||||
activity.startActivity(i)
|
}, null)
|
||||||
}, null)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.visibility(SWValidator { (activePlugin.activeBgSource as PluginBase).preferencesId > 0 }))
|
.visibility(SWValidator { (activePlugin.activeBgSource as PluginBase).preferencesId > 0 }))
|
||||||
private val screenProfile = SWScreen(injector, R.string.configbuilder_profile)
|
private val screenProfile = SWScreen(injector, R.string.configbuilder_profile)
|
||||||
|
@ -275,7 +273,7 @@ class SWDefinition @Inject constructor(
|
||||||
.label(R.string.profileswitch_ismissing))
|
.label(R.string.profileswitch_ismissing))
|
||||||
.add(SWButton(injector)
|
.add(SWButton(injector)
|
||||||
.text(R.string.doprofileswitch)
|
.text(R.string.doprofileswitch)
|
||||||
.action(Runnable { ProfileSwitchDialog().show(activity!!.supportFragmentManager, "SetupWizard") }))
|
.action(Runnable { ProfileSwitchDialog().show(activity.supportFragmentManager, "SetupWizard") }))
|
||||||
.validator(SWValidator { profileFunction.getProfile() != null })
|
.validator(SWValidator { profileFunction.getProfile() != null })
|
||||||
.visibility(SWValidator { profileFunction.getProfile() == null })
|
.visibility(SWValidator { profileFunction.getProfile() == null })
|
||||||
private val screenPump = SWScreen(injector, R.string.configbuilder_pump)
|
private val screenPump = SWScreen(injector, R.string.configbuilder_pump)
|
||||||
|
@ -288,13 +286,11 @@ class SWDefinition @Inject constructor(
|
||||||
.text(R.string.pumpsetup)
|
.text(R.string.pumpsetup)
|
||||||
.action(Runnable {
|
.action(Runnable {
|
||||||
val plugin = activePlugin.activePump as PluginBase
|
val plugin = activePlugin.activePump as PluginBase
|
||||||
activity?.let { activity ->
|
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable {
|
||||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable {
|
val i = Intent(activity, PreferencesActivity::class.java)
|
||||||
val i = Intent(activity, PreferencesActivity::class.java)
|
i.putExtra("id", plugin.preferencesId)
|
||||||
i.putExtra("id", plugin.preferencesId)
|
activity.startActivity(i)
|
||||||
activity.startActivity(i)
|
}, null)
|
||||||
}, null)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.visibility(SWValidator { (activePlugin.activePump as PluginBase).preferencesId > 0 }))
|
.visibility(SWValidator { (activePlugin.activePump as PluginBase).preferencesId > 0 }))
|
||||||
.add(SWButton(injector)
|
.add(SWButton(injector)
|
||||||
|
@ -317,13 +313,11 @@ class SWDefinition @Inject constructor(
|
||||||
.text(R.string.apssetup)
|
.text(R.string.apssetup)
|
||||||
.action(Runnable {
|
.action(Runnable {
|
||||||
val plugin = activePlugin.activeAPS as PluginBase
|
val plugin = activePlugin.activeAPS as PluginBase
|
||||||
activity?.let { activity ->
|
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable {
|
||||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable {
|
val i = Intent(activity, PreferencesActivity::class.java)
|
||||||
val i = Intent(activity, PreferencesActivity::class.java)
|
i.putExtra("id", plugin.preferencesId)
|
||||||
i.putExtra("id", plugin.preferencesId)
|
activity.startActivity(i)
|
||||||
activity.startActivity(i)
|
}, null)
|
||||||
}, null)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.visibility(SWValidator { (activePlugin.activeAPS as PluginBase).preferencesId > 0 }))
|
.visibility(SWValidator { (activePlugin.activeAPS as PluginBase).preferencesId > 0 }))
|
||||||
.visibility(SWValidator { Config.APS })
|
.visibility(SWValidator { Config.APS })
|
||||||
|
@ -367,13 +361,11 @@ class SWDefinition @Inject constructor(
|
||||||
.text(R.string.sensitivitysetup)
|
.text(R.string.sensitivitysetup)
|
||||||
.action(Runnable {
|
.action(Runnable {
|
||||||
val plugin = activePlugin.activeSensitivity as PluginBase
|
val plugin = activePlugin.activeSensitivity as PluginBase
|
||||||
activity?.let { activity ->
|
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable {
|
||||||
protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable {
|
val i = Intent(activity, PreferencesActivity::class.java)
|
||||||
val i = Intent(activity, PreferencesActivity::class.java)
|
i.putExtra("id", plugin.preferencesId)
|
||||||
i.putExtra("id", plugin.preferencesId)
|
activity.startActivity(i)
|
||||||
activity.startActivity(i)
|
}, null)
|
||||||
}, null)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.visibility(SWValidator { (activePlugin.activeSensitivity as PluginBase).preferencesId > 0 }))
|
.visibility(SWValidator { (activePlugin.activeSensitivity as PluginBase).preferencesId > 0 }))
|
||||||
private val getScreenObjectives = SWScreen(injector, R.string.objectives)
|
private val getScreenObjectives = SWScreen(injector, R.string.objectives)
|
||||||
|
|
|
@ -5,7 +5,7 @@ import androidx.fragment.app.Fragment
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.setupwizard.SWDefinition
|
import info.nightscout.androidaps.setupwizard.SWDefinition
|
||||||
|
|
||||||
class SWFragment(injecto:HasAndroidInjector, private var definition: SWDefinition) : SWItem(injecto, Type.FRAGMENT) {
|
class SWFragment(injector:HasAndroidInjector, private var definition: SWDefinition) : SWItem(injector, Type.FRAGMENT) {
|
||||||
lateinit var fragment: Fragment
|
lateinit var fragment: Fragment
|
||||||
|
|
||||||
fun add(fragment: Fragment): SWFragment {
|
fun add(fragment: Fragment): SWFragment {
|
||||||
|
@ -14,6 +14,6 @@ class SWFragment(injecto:HasAndroidInjector, private var definition: SWDefinitio
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun generateDialog(layout: LinearLayout) {
|
override fun generateDialog(layout: LinearLayout) {
|
||||||
definition.activity?.supportFragmentManager?.beginTransaction()?.add(layout.id, fragment, fragment.tag)?.commit()
|
definition.activity.supportFragmentManager.beginTransaction().add(layout.id, fragment, fragment.tag).commit()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,155 +0,0 @@
|
||||||
package info.nightscout.androidaps.utils;
|
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.ActivityNotFoundException;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.PowerManager;
|
|
||||||
import android.provider.Settings;
|
|
||||||
|
|
||||||
import androidx.core.app.ActivityCompat;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
|
|
||||||
import info.nightscout.androidaps.MainApp;
|
|
||||||
import info.nightscout.androidaps.R;
|
|
||||||
import info.nightscout.androidaps.interfaces.PluginType;
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction;
|
|
||||||
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin;
|
|
||||||
|
|
||||||
public class AndroidPermission {
|
|
||||||
|
|
||||||
public static final int CASE_STORAGE = 0x1;
|
|
||||||
public static final int CASE_SMS = 0x2;
|
|
||||||
public static final int CASE_LOCATION = 0x3;
|
|
||||||
public static final int CASE_BATTERY = 0x4;
|
|
||||||
public static final int CASE_PHONE_STATE = 0x5;
|
|
||||||
public static final int CASE_SYSTEM_WINDOW = 0x6;
|
|
||||||
|
|
||||||
private static boolean permission_battery_optimization_failed = false;
|
|
||||||
|
|
||||||
@SuppressLint("BatteryLife")
|
|
||||||
private static void askForPermission(Activity activity, String[] permission, Integer requestCode) {
|
|
||||||
boolean test = false;
|
|
||||||
boolean testBattery = false;
|
|
||||||
for (String s : permission) {
|
|
||||||
test = test || (ContextCompat.checkSelfPermission(activity, s) != PackageManager.PERMISSION_GRANTED);
|
|
||||||
if (s.equals(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)) {
|
|
||||||
PowerManager powerManager = (PowerManager) activity.getSystemService(Context.POWER_SERVICE);
|
|
||||||
String packageName = activity.getPackageName();
|
|
||||||
testBattery = testBattery || !powerManager.isIgnoringBatteryOptimizations(packageName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (test) {
|
|
||||||
ActivityCompat.requestPermissions(activity, permission, requestCode);
|
|
||||||
}
|
|
||||||
if (testBattery) {
|
|
||||||
try {
|
|
||||||
Intent i = new Intent();
|
|
||||||
i.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
|
|
||||||
i.setData(Uri.parse("package:" + activity.getPackageName()));
|
|
||||||
activity.startActivityForResult(i, CASE_BATTERY);
|
|
||||||
} catch (ActivityNotFoundException e) {
|
|
||||||
permission_battery_optimization_failed = true;
|
|
||||||
OKDialog.show(activity, MainApp.gs(R.string.permission), MainApp.gs(R.string.alert_dialog_permission_battery_optimization_failed), activity::recreate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void askForPermission(Activity activity, String permission, Integer requestCode) {
|
|
||||||
String[] permissions = {permission};
|
|
||||||
askForPermission(activity, permissions, requestCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean permissionNotGranted(Context context, String permission) {
|
|
||||||
boolean selfCheck = ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
|
|
||||||
if (permission.equals(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)) {
|
|
||||||
if (!permission_battery_optimization_failed) {
|
|
||||||
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
|
||||||
String packageName = context.getPackageName();
|
|
||||||
selfCheck = selfCheck && powerManager.isIgnoringBatteryOptimizations(packageName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return !selfCheck;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static synchronized void notifyForSMSPermissions(Activity activity, SmsCommunicatorPlugin smsCommunicatorPlugin) {
|
|
||||||
if (smsCommunicatorPlugin.isEnabled(PluginType.GENERAL)) {
|
|
||||||
if (permissionNotGranted(activity, Manifest.permission.RECEIVE_SMS)) {
|
|
||||||
NotificationWithAction notification = new NotificationWithAction(MainApp.instance(), Notification.PERMISSION_SMS, MainApp.gs(R.string.smscommunicator_missingsmspermission), Notification.URGENT);
|
|
||||||
notification.action(R.string.request, () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.RECEIVE_SMS,
|
|
||||||
Manifest.permission.SEND_SMS,
|
|
||||||
Manifest.permission.RECEIVE_MMS}, AndroidPermission.CASE_SMS));
|
|
||||||
RxBus.Companion.getINSTANCE().send(new EventNewNotification(notification));
|
|
||||||
} else
|
|
||||||
RxBus.Companion.getINSTANCE().send(new EventDismissNotification(Notification.PERMISSION_SMS));
|
|
||||||
// Following is a bug in Android 8
|
|
||||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O) {
|
|
||||||
if (permissionNotGranted(activity, Manifest.permission.READ_PHONE_STATE)) {
|
|
||||||
NotificationWithAction notification = new NotificationWithAction(MainApp.instance(), Notification.PERMISSION_PHONESTATE, MainApp.gs(R.string.smscommunicator_missingphonestatepermission), Notification.URGENT);
|
|
||||||
notification.action(R.string.request, () ->
|
|
||||||
AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.READ_PHONE_STATE}, AndroidPermission.CASE_PHONE_STATE));
|
|
||||||
RxBus.Companion.getINSTANCE().send(new EventNewNotification(notification));
|
|
||||||
} else
|
|
||||||
RxBus.Companion.getINSTANCE().send(new EventDismissNotification(Notification.PERMISSION_PHONESTATE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static synchronized void notifyForBatteryOptimizationPermission(Activity activity) {
|
|
||||||
if (permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)) {
|
|
||||||
NotificationWithAction notification = new NotificationWithAction(MainApp.instance(), Notification.PERMISSION_BATTERY, String.format(MainApp.gs(R.string.needwhitelisting), MainApp.gs(R.string.app_name)), Notification.URGENT);
|
|
||||||
notification.action(R.string.request, () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}, AndroidPermission.CASE_BATTERY));
|
|
||||||
RxBus.Companion.getINSTANCE().send(new EventNewNotification(notification));
|
|
||||||
} else
|
|
||||||
RxBus.Companion.getINSTANCE().send(new EventDismissNotification(Notification.PERMISSION_BATTERY));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static synchronized void notifyForStoragePermission(Activity activity) {
|
|
||||||
if (permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
|
||||||
NotificationWithAction notification = new NotificationWithAction(MainApp.instance(), Notification.PERMISSION_STORAGE, MainApp.gs(R.string.needstoragepermission), Notification.URGENT);
|
|
||||||
notification.action(R.string.request, () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
|
|
||||||
Manifest.permission.WRITE_EXTERNAL_STORAGE}, AndroidPermission.CASE_STORAGE));
|
|
||||||
RxBus.Companion.getINSTANCE().send(new EventNewNotification(notification));
|
|
||||||
} else
|
|
||||||
RxBus.Companion.getINSTANCE().send(new EventDismissNotification(Notification.PERMISSION_STORAGE));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static synchronized void notifyForLocationPermissions(Activity activity) {
|
|
||||||
if (permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION)) {
|
|
||||||
NotificationWithAction notification = new NotificationWithAction(MainApp.instance(), Notification.PERMISSION_LOCATION, MainApp.gs(R.string.needlocationpermission), Notification.URGENT);
|
|
||||||
notification.action(R.string.request, () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, AndroidPermission.CASE_LOCATION));
|
|
||||||
RxBus.Companion.getINSTANCE().send(new EventNewNotification(notification));
|
|
||||||
} else
|
|
||||||
RxBus.Companion.getINSTANCE().send(new EventDismissNotification(Notification.PERMISSION_LOCATION));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static synchronized void notifyForSystemWindowPermissions(Activity activity) {
|
|
||||||
// Check if Android Q or higher
|
|
||||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
|
|
||||||
if (!Settings.canDrawOverlays(activity)) {
|
|
||||||
NotificationWithAction notification = new NotificationWithAction(MainApp.instance(), Notification.PERMISSION_SYSTEM_WINDOW, MainApp.gs(R.string.needsystemwindowpermission), Notification.URGENT);
|
|
||||||
notification.action(R.string.request, () -> {
|
|
||||||
// Check if Android Q or higher
|
|
||||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
|
|
||||||
// Show alert dialog to the user saying a separate permission is needed
|
|
||||||
// Launch the settings activity if the user prefers
|
|
||||||
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
|
||||||
Uri.parse("package:" + activity.getPackageName()));
|
|
||||||
activity.startActivity(intent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
RxBus.Companion.getINSTANCE().send(new EventNewNotification(notification));
|
|
||||||
} else
|
|
||||||
RxBus.Companion.getINSTANCE().send(new EventDismissNotification(Notification.PERMISSION_SYSTEM_WINDOW));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
package info.nightscout.androidaps.utils
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.ActivityNotFoundException
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.PowerManager
|
||||||
|
import android.provider.Settings
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import dagger.android.HasAndroidInjector
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.interfaces.PluginType
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction
|
||||||
|
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin
|
||||||
|
import info.nightscout.androidaps.utils.OKDialog.show
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class AndroidPermission @Inject constructor(
|
||||||
|
val resourceHelper: ResourceHelper,
|
||||||
|
val rxBus: RxBusWrapper,
|
||||||
|
val injector: HasAndroidInjector
|
||||||
|
) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val CASE_STORAGE = 0x1
|
||||||
|
const val CASE_SMS = 0x2
|
||||||
|
const val CASE_LOCATION = 0x3
|
||||||
|
const val CASE_BATTERY = 0x4
|
||||||
|
const val CASE_PHONE_STATE = 0x5
|
||||||
|
const val CASE_SYSTEM_WINDOW = 0x6
|
||||||
|
}
|
||||||
|
|
||||||
|
private var permission_battery_optimization_failed = false
|
||||||
|
|
||||||
|
@SuppressLint("BatteryLife")
|
||||||
|
private fun askForPermission(activity: Activity, permission: Array<String>, requestCode: Int) {
|
||||||
|
var test = false
|
||||||
|
var testBattery = false
|
||||||
|
for (s in permission) {
|
||||||
|
test = test || ContextCompat.checkSelfPermission(activity, s) != PackageManager.PERMISSION_GRANTED
|
||||||
|
if (s == Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) {
|
||||||
|
val powerManager = activity.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||||
|
val packageName = activity.packageName
|
||||||
|
testBattery = testBattery || !powerManager.isIgnoringBatteryOptimizations(packageName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (test) {
|
||||||
|
ActivityCompat.requestPermissions(activity, permission, requestCode)
|
||||||
|
}
|
||||||
|
if (testBattery) {
|
||||||
|
try {
|
||||||
|
val i = Intent()
|
||||||
|
i.action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
|
||||||
|
i.data = Uri.parse("package:" + activity.packageName)
|
||||||
|
activity.startActivityForResult(i, CASE_BATTERY)
|
||||||
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
permission_battery_optimization_failed = true
|
||||||
|
show(activity, resourceHelper.gs(R.string.permission), resourceHelper.gs(R.string.alert_dialog_permission_battery_optimization_failed), Runnable { activity.recreate() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun askForPermission(activity: Activity, permission: String, requestCode: Int) {
|
||||||
|
val permissions = arrayOf(permission)
|
||||||
|
askForPermission(activity, permissions, requestCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun permissionNotGranted(context: Context, permission: String): Boolean {
|
||||||
|
var selfCheck = ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED
|
||||||
|
if (permission == Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) {
|
||||||
|
if (!permission_battery_optimization_failed) {
|
||||||
|
val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||||
|
val packageName = context.packageName
|
||||||
|
selfCheck = selfCheck && powerManager.isIgnoringBatteryOptimizations(packageName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !selfCheck
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun notifyForSMSPermissions(activity: Activity, smsCommunicatorPlugin: SmsCommunicatorPlugin) {
|
||||||
|
if (smsCommunicatorPlugin.isEnabled(PluginType.GENERAL)) {
|
||||||
|
if (permissionNotGranted(activity, Manifest.permission.RECEIVE_SMS)) {
|
||||||
|
val notification = NotificationWithAction(injector, Notification.PERMISSION_SMS, resourceHelper.gs(R.string.smscommunicator_missingsmspermission), Notification.URGENT)
|
||||||
|
notification.action(R.string.request, Runnable {
|
||||||
|
askForPermission(activity, arrayOf(Manifest.permission.RECEIVE_SMS,
|
||||||
|
Manifest.permission.SEND_SMS,
|
||||||
|
Manifest.permission.RECEIVE_MMS), CASE_SMS)
|
||||||
|
})
|
||||||
|
rxBus.send(EventNewNotification(notification))
|
||||||
|
} else rxBus.send(EventDismissNotification(Notification.PERMISSION_SMS))
|
||||||
|
// Following is a bug in Android 8
|
||||||
|
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O) {
|
||||||
|
if (permissionNotGranted(activity, Manifest.permission.READ_PHONE_STATE)) {
|
||||||
|
val notification = NotificationWithAction(injector, Notification.PERMISSION_PHONESTATE, resourceHelper.gs(R.string.smscommunicator_missingphonestatepermission), Notification.URGENT)
|
||||||
|
notification.action(R.string.request, Runnable { askForPermission(activity, arrayOf(Manifest.permission.READ_PHONE_STATE), CASE_PHONE_STATE) })
|
||||||
|
rxBus.send(EventNewNotification(notification))
|
||||||
|
} else rxBus.send(EventDismissNotification(Notification.PERMISSION_PHONESTATE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun notifyForBatteryOptimizationPermission(activity: Activity) {
|
||||||
|
if (permissionNotGranted(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)) {
|
||||||
|
val notification = NotificationWithAction(injector, Notification.PERMISSION_BATTERY, String.format(resourceHelper.gs(R.string.needwhitelisting), resourceHelper.gs(R.string.app_name)), Notification.URGENT)
|
||||||
|
notification.action(R.string.request, Runnable { askForPermission(activity, arrayOf(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS), CASE_BATTERY) })
|
||||||
|
rxBus.send(EventNewNotification(notification))
|
||||||
|
} else rxBus.send(EventDismissNotification(Notification.PERMISSION_BATTERY))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized fun notifyForStoragePermission(activity: Activity) {
|
||||||
|
if (permissionNotGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||||
|
val notification = NotificationWithAction(injector, Notification.PERMISSION_STORAGE, resourceHelper.gs(R.string.needstoragepermission), Notification.URGENT)
|
||||||
|
notification.action(R.string.request, Runnable {
|
||||||
|
askForPermission(activity, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||||
|
Manifest.permission.WRITE_EXTERNAL_STORAGE), CASE_STORAGE)
|
||||||
|
})
|
||||||
|
rxBus.send(EventNewNotification(notification))
|
||||||
|
} else rxBus.send(EventDismissNotification(Notification.PERMISSION_STORAGE))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized fun notifyForLocationPermissions(activity: Activity) {
|
||||||
|
if (permissionNotGranted(activity, Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||||
|
val notification = NotificationWithAction(injector, Notification.PERMISSION_LOCATION, resourceHelper.gs(R.string.needlocationpermission), Notification.URGENT)
|
||||||
|
notification.action(R.string.request, Runnable { askForPermission(activity, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), CASE_LOCATION) })
|
||||||
|
rxBus.send(EventNewNotification(notification))
|
||||||
|
} else rxBus.send(EventDismissNotification(Notification.PERMISSION_LOCATION))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized fun notifyForSystemWindowPermissions(activity: Activity) {
|
||||||
|
// Check if Android Q or higher
|
||||||
|
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
|
||||||
|
if (!Settings.canDrawOverlays(activity)) {
|
||||||
|
val notification = NotificationWithAction(injector, Notification.PERMISSION_SYSTEM_WINDOW, resourceHelper.gs(R.string.needsystemwindowpermission), Notification.URGENT)
|
||||||
|
notification.action(R.string.request, Runnable {
|
||||||
|
// Check if Android Q or higher
|
||||||
|
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
|
||||||
|
// Show alert dialog to the user saying a separate permission is needed
|
||||||
|
// Launch the settings activity if the user prefers
|
||||||
|
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
||||||
|
Uri.parse("package:" + activity.packageName))
|
||||||
|
activity.startActivity(intent)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
rxBus.send(EventNewNotification(notification))
|
||||||
|
} else rxBus.send(EventDismissNotification(Notification.PERMISSION_SYSTEM_WINDOW))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
142
app/src/main/java/info/nightscout/androidaps/utils/CryptoUtil.kt
Normal file
142
app/src/main/java/info/nightscout/androidaps/utils/CryptoUtil.kt
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
package info.nightscout.androidaps.utils
|
||||||
|
|
||||||
|
import org.spongycastle.util.encoders.Base64
|
||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.security.MessageDigest
|
||||||
|
import java.security.SecureRandom
|
||||||
|
import java.security.spec.KeySpec
|
||||||
|
import javax.crypto.Cipher
|
||||||
|
import javax.crypto.Mac
|
||||||
|
import javax.crypto.SecretKey
|
||||||
|
import javax.crypto.SecretKeyFactory
|
||||||
|
import javax.crypto.spec.GCMParameterSpec
|
||||||
|
import javax.crypto.spec.PBEKeySpec
|
||||||
|
import javax.crypto.spec.SecretKeySpec
|
||||||
|
|
||||||
|
private val HEX_CHARS = "0123456789abcdef"
|
||||||
|
private val HEX_CHARS_ARRAY = "0123456789abcdef".toCharArray()
|
||||||
|
|
||||||
|
fun String.hexStringToByteArray() : ByteArray {
|
||||||
|
|
||||||
|
val upperCased = this.toLowerCase()
|
||||||
|
val result = ByteArray(length / 2)
|
||||||
|
for (i in 0 until length step 2) {
|
||||||
|
val firstIndex = HEX_CHARS.indexOf(upperCased[i]);
|
||||||
|
val secondIndex = HEX_CHARS.indexOf(upperCased[i + 1]);
|
||||||
|
|
||||||
|
val octet = firstIndex.shl(4).or(secondIndex)
|
||||||
|
result.set(i.shr(1), octet.toByte())
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ByteArray.toHex() : String{
|
||||||
|
val result = StringBuffer()
|
||||||
|
|
||||||
|
forEach {
|
||||||
|
val octet = it.toInt()
|
||||||
|
val firstIndex = (octet and 0xF0).ushr(4)
|
||||||
|
val secondIndex = octet and 0x0F
|
||||||
|
result.append(HEX_CHARS_ARRAY[firstIndex])
|
||||||
|
result.append(HEX_CHARS_ARRAY[secondIndex])
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
object CryptoUtil {
|
||||||
|
|
||||||
|
private const val IV_LENGTH_BYTE = 12
|
||||||
|
private const val TAG_LENGTH_BIT = 128
|
||||||
|
private const val AES_KEY_SIZE_BIT = 256
|
||||||
|
private const val PBKDF2_ITERATIONS = 50000 // check delays it cause on real device
|
||||||
|
private const val SALT_SIZE_BYTE = 32
|
||||||
|
|
||||||
|
private val secureRandom: SecureRandom = SecureRandom()
|
||||||
|
|
||||||
|
fun sha256(source: String): String {
|
||||||
|
val digest = MessageDigest.getInstance("SHA-256")
|
||||||
|
val hashRaw = digest.digest(source.toByteArray())
|
||||||
|
return hashRaw.toHex()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hmac256(str: String, secret: String): String? {
|
||||||
|
val sha256_HMAC = Mac.getInstance("HmacSHA256")
|
||||||
|
val secretKey = SecretKeySpec(secret.toByteArray(), "HmacSHA256")
|
||||||
|
sha256_HMAC.init(secretKey)
|
||||||
|
return sha256_HMAC.doFinal(str.toByteArray()).toHex()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun prepCipherKey(passPhrase: String, salt:ByteArray, iterationCount:Int = PBKDF2_ITERATIONS, keyStrength:Int = AES_KEY_SIZE_BIT): SecretKeySpec {
|
||||||
|
val factory: SecretKeyFactory = SecretKeyFactory.getInstance("PBKDF2withHmacSHA1")
|
||||||
|
val spec: KeySpec = PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount, keyStrength)
|
||||||
|
val tmp: SecretKey = factory.generateSecret(spec)
|
||||||
|
return SecretKeySpec(tmp.getEncoded(), "AES")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mineSalt(len :Int = SALT_SIZE_BYTE): ByteArray {
|
||||||
|
val salt = ByteArray(len)
|
||||||
|
secureRandom.nextBytes(salt)
|
||||||
|
return salt
|
||||||
|
}
|
||||||
|
|
||||||
|
fun encrypt(passPhrase: String, salt:ByteArray, rawData: String ): String? {
|
||||||
|
val iv: ByteArray?
|
||||||
|
val encrypted: ByteArray?
|
||||||
|
return try {
|
||||||
|
iv = ByteArray(IV_LENGTH_BYTE)
|
||||||
|
secureRandom.nextBytes(iv)
|
||||||
|
val cipherEnc: Cipher = Cipher.getInstance("AES/GCM/NoPadding")
|
||||||
|
cipherEnc.init(Cipher.ENCRYPT_MODE, prepCipherKey(passPhrase, salt), GCMParameterSpec(TAG_LENGTH_BIT, iv))
|
||||||
|
encrypted = cipherEnc.doFinal(rawData.toByteArray())
|
||||||
|
val byteBuffer: ByteBuffer = ByteBuffer.allocate(1 + iv.size + encrypted.size)
|
||||||
|
byteBuffer.put(iv.size.toByte())
|
||||||
|
byteBuffer.put(iv)
|
||||||
|
byteBuffer.put(encrypted)
|
||||||
|
String(Base64.encode(byteBuffer.array()))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun decrypt(passPhrase: String, salt:ByteArray, encryptedData: String): String? {
|
||||||
|
val iv: ByteArray?
|
||||||
|
val encrypted: ByteArray?
|
||||||
|
return try {
|
||||||
|
val byteBuffer = ByteBuffer.wrap(Base64.decode(encryptedData))
|
||||||
|
val ivLength = byteBuffer.get().toInt()
|
||||||
|
iv = ByteArray(ivLength)
|
||||||
|
byteBuffer[iv]
|
||||||
|
encrypted = ByteArray(byteBuffer.remaining())
|
||||||
|
byteBuffer[encrypted]
|
||||||
|
val cipherDec: Cipher = Cipher.getInstance("AES/GCM/NoPadding")
|
||||||
|
cipherDec.init(Cipher.DECRYPT_MODE, prepCipherKey(passPhrase, salt), GCMParameterSpec(TAG_LENGTH_BIT, iv))
|
||||||
|
val dec = cipherDec.doFinal(encrypted)
|
||||||
|
String(dec)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkPassword(password: String, referenceHash: String): Boolean {
|
||||||
|
return if (referenceHash.startsWith("hmac:")) {
|
||||||
|
val hashSegments = referenceHash.split(":")
|
||||||
|
if (hashSegments.size != 3)
|
||||||
|
return false
|
||||||
|
return hmac256(password, hashSegments[1]) == hashSegments[2]
|
||||||
|
} else {
|
||||||
|
password == referenceHash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hashPassword(password: String): String {
|
||||||
|
return if (!password.startsWith("hmac:")) {
|
||||||
|
val salt = mineSalt().toHex()
|
||||||
|
return "hmac:${salt}:${hmac256(password, salt)}"
|
||||||
|
} else {
|
||||||
|
password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -108,6 +108,28 @@ public class DateUtil {
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long toTodayTime(String hh_colon_mm) {
|
||||||
|
Pattern p = Pattern.compile("(\\d+):(\\d+)( a.m.| p.m.| AM| PM|AM|PM|)");
|
||||||
|
Matcher m = p.matcher(hh_colon_mm);
|
||||||
|
long retval = 0;
|
||||||
|
|
||||||
|
if (m.find()) {
|
||||||
|
int hours = SafeParse.stringToInt(m.group(1));
|
||||||
|
int minutes = SafeParse.stringToInt(m.group(2));
|
||||||
|
if ((m.group(3).equals(" a.m.") || m.group(3).equals(" AM") || m.group(3).equals("AM")) && m.group(1).equals("12"))
|
||||||
|
hours -= 12;
|
||||||
|
if ((m.group(3).equals(" p.m.") || m.group(3).equals(" PM") || m.group(3).equals("PM")) && !(m.group(1).equals("12")))
|
||||||
|
hours += 12;
|
||||||
|
Calendar c = Calendar.getInstance();
|
||||||
|
c.set(Calendar.HOUR_OF_DAY, hours);
|
||||||
|
c.set(Calendar.MINUTE, minutes);
|
||||||
|
c.set(Calendar.SECOND, 0);
|
||||||
|
c.set(Calendar.MILLISECOND, 0);
|
||||||
|
retval = c.getTimeInMillis();
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
public static String dateString(Date date) {
|
public static String dateString(Date date) {
|
||||||
DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
|
DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
|
||||||
return df.format(date);
|
return df.format(date);
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.os.Bundle
|
||||||
import com.crashlytics.android.Crashlytics
|
import com.crashlytics.android.Crashlytics
|
||||||
import com.google.firebase.analytics.FirebaseAnalytics
|
import com.google.firebase.analytics.FirebaseAnalytics
|
||||||
import info.nightscout.androidaps.BuildConfig
|
import info.nightscout.androidaps.BuildConfig
|
||||||
|
import info.nightscout.androidaps.Config
|
||||||
import info.nightscout.androidaps.MainApp
|
import info.nightscout.androidaps.MainApp
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||||
|
@ -132,7 +133,8 @@ class FabricPrivacy @Inject constructor(
|
||||||
val hashes: List<String> = signatureVerifierPlugin.shortHashes()
|
val hashes: List<String> = signatureVerifierPlugin.shortHashes()
|
||||||
if (hashes.isNotEmpty()) mainApp.firebaseAnalytics.setUserProperty("Hash", hashes[0])
|
if (hashes.isNotEmpty()) mainApp.firebaseAnalytics.setUserProperty("Hash", hashes[0])
|
||||||
activePlugin.activePump.let { mainApp.firebaseAnalytics.setUserProperty("Pump", it::class.java.simpleName) }
|
activePlugin.activePump.let { mainApp.firebaseAnalytics.setUserProperty("Pump", it::class.java.simpleName) }
|
||||||
activePlugin.activeAPS.let { mainApp.firebaseAnalytics.setUserProperty("Aps", it::class.java.simpleName) }
|
if (!Config.NSCLIENT && !Config.PUMPCONTROL)
|
||||||
|
activePlugin.activeAPS.let { mainApp.firebaseAnalytics.setUserProperty("Aps", it::class.java.simpleName) }
|
||||||
activePlugin.activeBgSource.let { mainApp.firebaseAnalytics.setUserProperty("BgSource", it::class.java.simpleName) }
|
activePlugin.activeBgSource.let { mainApp.firebaseAnalytics.setUserProperty("BgSource", it::class.java.simpleName) }
|
||||||
mainApp.firebaseAnalytics.setUserProperty("Profile", activePlugin.activeProfileInterface.javaClass.simpleName)
|
mainApp.firebaseAnalytics.setUserProperty("Profile", activePlugin.activeProfileInterface.javaClass.simpleName)
|
||||||
activePlugin.activeSensitivity.let { mainApp.firebaseAnalytics.setUserProperty("Sensitivity", it::class.java.simpleName) }
|
activePlugin.activeSensitivity.let { mainApp.firebaseAnalytics.setUserProperty("Sensitivity", it::class.java.simpleName) }
|
||||||
|
|
|
@ -4,16 +4,19 @@ import android.content.Context
|
||||||
import android.content.ContextWrapper
|
import android.content.ContextWrapper
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.LocaleList
|
import android.os.LocaleList
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
object LocaleHelper {
|
object LocaleHelper {
|
||||||
fun currentLanguage(): String =
|
private fun currentLanguage(context: Context): String =
|
||||||
SP.getString(R.string.key_language, Locale.getDefault().language)
|
PreferenceManager.getDefaultSharedPreferences(context).getString(context.getString(R.string.key_language), "en")
|
||||||
|
?: "en"
|
||||||
|
// injection not possible because of use in attachBaseContext
|
||||||
|
//SP.getString(R.string.key_language, Locale.getDefault().language)
|
||||||
|
|
||||||
private fun currentLocale(): Locale {
|
private fun currentLocale(context: Context): Locale {
|
||||||
val language = currentLanguage()
|
val language = currentLanguage(context)
|
||||||
var locale = Locale(language)
|
var locale = Locale(language)
|
||||||
if (language.contains("_")) {
|
if (language.contains("_")) {
|
||||||
// language with country like pt_BR defined in arrays.xml
|
// language with country like pt_BR defined in arrays.xml
|
||||||
|
@ -26,7 +29,7 @@ object LocaleHelper {
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
fun update(context: Context) {
|
fun update(context: Context) {
|
||||||
val locale = currentLocale()
|
val locale = currentLocale(context)
|
||||||
Locale.setDefault(locale)
|
Locale.setDefault(locale)
|
||||||
val resources = context.resources
|
val resources = context.resources
|
||||||
val configuration = resources.configuration
|
val configuration = resources.configuration
|
||||||
|
@ -39,7 +42,7 @@ object LocaleHelper {
|
||||||
fun wrap(ctx: Context): ContextWrapper {
|
fun wrap(ctx: Context): ContextWrapper {
|
||||||
val res = ctx.resources
|
val res = ctx.resources
|
||||||
val configuration = res.configuration
|
val configuration = res.configuration
|
||||||
val newLocale = currentLocale()
|
val newLocale = currentLocale(ctx)
|
||||||
val context = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
val context = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
configuration.setLocale(newLocale)
|
configuration.setLocale(newLocale)
|
||||||
val localeList = LocaleList(newLocale)
|
val localeList = LocaleList(newLocale)
|
||||||
|
|
|
@ -21,6 +21,17 @@ public class MidnightTime {
|
||||||
return c.getTimeInMillis();
|
return c.getTimeInMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long calcPlusMinutes(int minutes) {
|
||||||
|
int h = minutes / 60;
|
||||||
|
int m = minutes % 60;
|
||||||
|
Calendar c = Calendar.getInstance();
|
||||||
|
c.set(Calendar.HOUR_OF_DAY, h);
|
||||||
|
c.set(Calendar.MINUTE, m);
|
||||||
|
c.set(Calendar.SECOND, 0);
|
||||||
|
c.set(Calendar.MILLISECOND, 0);
|
||||||
|
return c.getTimeInMillis();
|
||||||
|
}
|
||||||
|
|
||||||
public static long calc(long time) {
|
public static long calc(long time) {
|
||||||
Long m;
|
Long m;
|
||||||
synchronized (times) {
|
synchronized (times) {
|
||||||
|
|
|
@ -4,17 +4,10 @@ import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.os.Handler
|
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.appcompat.view.ContextThemeWrapper
|
|
||||||
import info.nightscout.androidaps.MainApp
|
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.utils.alertDialogs.AlertDialogHelper
|
||||||
|
|
||||||
object OKDialog {
|
object OKDialog {
|
||||||
@SuppressLint("InflateParams")
|
@SuppressLint("InflateParams")
|
||||||
|
@ -23,11 +16,9 @@ object OKDialog {
|
||||||
fun show(context: Context, title: String, message: String, runnable: Runnable? = null) {
|
fun show(context: Context, title: String, message: String, runnable: Runnable? = null) {
|
||||||
var notEmptytitle = title
|
var notEmptytitle = title
|
||||||
if (notEmptytitle.isEmpty()) notEmptytitle = context.getString(R.string.message)
|
if (notEmptytitle.isEmpty()) notEmptytitle = context.getString(R.string.message)
|
||||||
val titleLayout = LayoutInflater.from(context).inflate(R.layout.dialog_alert_custom, null)
|
|
||||||
(titleLayout.findViewById<View>(R.id.alertdialog_title) as TextView).text = notEmptytitle
|
AlertDialogHelper.Builder(context)
|
||||||
(titleLayout.findViewById<View>(R.id.alertdialog_icon) as ImageView).setImageResource(R.drawable.ic_check_while_48dp)
|
.setCustomTitle(AlertDialogHelper.buildCustomTitle(context, notEmptytitle))
|
||||||
AlertDialog.Builder(ContextThemeWrapper(context, R.style.AppTheme))
|
|
||||||
.setCustomTitle(titleLayout)
|
|
||||||
.setMessage(message)
|
.setMessage(message)
|
||||||
.setPositiveButton(context.getString(R.string.ok)) { dialog: DialogInterface, _: Int ->
|
.setPositiveButton(context.getString(R.string.ok)) { dialog: DialogInterface, _: Int ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
|
@ -38,22 +29,15 @@ object OKDialog {
|
||||||
.setCanceledOnTouchOutside(false)
|
.setCanceledOnTouchOutside(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun runOnUiThread(theRunnable: Runnable?) {
|
|
||||||
val mainHandler = Handler(MainApp.instance().applicationContext.mainLooper)
|
|
||||||
theRunnable?.let { mainHandler.post(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("InflateParams")
|
@SuppressLint("InflateParams")
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun show(activity: Activity, title: String, message: Spanned, runnable: Runnable? = null) {
|
fun show(activity: Activity, title: String, message: Spanned, runnable: Runnable? = null) {
|
||||||
var notEmptytitle = title
|
var notEmptytitle = title
|
||||||
if (notEmptytitle.isEmpty()) notEmptytitle = activity.getString(R.string.message)
|
if (notEmptytitle.isEmpty()) notEmptytitle = activity.getString(R.string.message)
|
||||||
val titleLayout = activity.layoutInflater.inflate(R.layout.dialog_alert_custom, null)
|
|
||||||
(titleLayout.findViewById<View>(R.id.alertdialog_title) as TextView).text = notEmptytitle
|
AlertDialogHelper.Builder(activity)
|
||||||
(titleLayout.findViewById<View>(R.id.alertdialog_icon) as ImageView).setImageResource(R.drawable.ic_check_while_48dp)
|
.setCustomTitle(AlertDialogHelper.buildCustomTitle(activity, notEmptytitle))
|
||||||
AlertDialog.Builder(ContextThemeWrapper(activity, R.style.AppTheme))
|
|
||||||
.setCustomTitle(titleLayout)
|
|
||||||
.setMessage(message)
|
.setMessage(message)
|
||||||
.setPositiveButton(activity.getString(R.string.ok)) { dialog: DialogInterface, _: Int ->
|
.setPositiveButton(activity.getString(R.string.ok)) { dialog: DialogInterface, _: Int ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
|
@ -78,12 +62,9 @@ object OKDialog {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun showConfirmation(activity: Activity, title: String, message: Spanned, ok: Runnable?, cancel: Runnable? = null) {
|
fun showConfirmation(activity: Activity, title: String, message: Spanned, ok: Runnable?, cancel: Runnable? = null) {
|
||||||
val titleLayout = activity.layoutInflater.inflate(R.layout.dialog_alert_custom, null)
|
AlertDialogHelper.Builder(activity)
|
||||||
(titleLayout.findViewById<View>(R.id.alertdialog_title) as TextView).text = title
|
|
||||||
(titleLayout.findViewById<View>(R.id.alertdialog_icon) as ImageView).setImageResource(R.drawable.ic_check_while_48dp)
|
|
||||||
AlertDialog.Builder(ContextThemeWrapper(activity, R.style.AppTheme))
|
|
||||||
.setMessage(message)
|
.setMessage(message)
|
||||||
.setCustomTitle(titleLayout)
|
.setCustomTitle(AlertDialogHelper.buildCustomTitle(activity, title))
|
||||||
.setPositiveButton(android.R.string.ok) { dialog: DialogInterface, _: Int ->
|
.setPositiveButton(android.R.string.ok) { dialog: DialogInterface, _: Int ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
SystemClock.sleep(100)
|
SystemClock.sleep(100)
|
||||||
|
@ -102,12 +83,9 @@ object OKDialog {
|
||||||
@SuppressLint("InflateParams")
|
@SuppressLint("InflateParams")
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun showConfirmation(activity: Activity, title: String, message: String, ok: Runnable?, cancel: Runnable? = null) {
|
fun showConfirmation(activity: Activity, title: String, message: String, ok: Runnable?, cancel: Runnable? = null) {
|
||||||
val titleLayout = activity.layoutInflater.inflate(R.layout.dialog_alert_custom, null)
|
AlertDialogHelper.Builder(activity)
|
||||||
(titleLayout.findViewById<View>(R.id.alertdialog_title) as TextView).text = title
|
|
||||||
(titleLayout.findViewById<View>(R.id.alertdialog_icon) as ImageView).setImageResource(R.drawable.ic_check_while_48dp)
|
|
||||||
AlertDialog.Builder(ContextThemeWrapper(activity, R.style.AppTheme))
|
|
||||||
.setMessage(message)
|
.setMessage(message)
|
||||||
.setCustomTitle(titleLayout)
|
.setCustomTitle(AlertDialogHelper.buildCustomTitle(activity, title))
|
||||||
.setPositiveButton(android.R.string.ok) { dialog: DialogInterface, _: Int ->
|
.setPositiveButton(android.R.string.ok) { dialog: DialogInterface, _: Int ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
SystemClock.sleep(100)
|
SystemClock.sleep(100)
|
||||||
|
@ -132,12 +110,9 @@ object OKDialog {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun showConfirmation(context: Context, title: String, message: Spanned, ok: Runnable?, cancel: Runnable? = null) {
|
fun showConfirmation(context: Context, title: String, message: Spanned, ok: Runnable?, cancel: Runnable? = null) {
|
||||||
val titleLayout = LayoutInflater.from(context).inflate(R.layout.dialog_alert_custom, null)
|
AlertDialogHelper.Builder(context)
|
||||||
(titleLayout.findViewById<View>(R.id.alertdialog_title) as TextView).text = title
|
|
||||||
(titleLayout.findViewById<View>(R.id.alertdialog_icon) as ImageView).setImageResource(R.drawable.ic_check_while_48dp)
|
|
||||||
AlertDialog.Builder(ContextThemeWrapper(context, R.style.AppTheme))
|
|
||||||
.setMessage(message)
|
.setMessage(message)
|
||||||
.setCustomTitle(titleLayout)
|
.setCustomTitle(AlertDialogHelper.buildCustomTitle(context, title))
|
||||||
.setPositiveButton(android.R.string.ok) { dialog: DialogInterface, _: Int ->
|
.setPositiveButton(android.R.string.ok) { dialog: DialogInterface, _: Int ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
SystemClock.sleep(100)
|
SystemClock.sleep(100)
|
||||||
|
@ -163,12 +138,9 @@ object OKDialog {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun showConfirmation(context: Context, title: String, message: String, ok: Runnable?, cancel: Runnable? = null) {
|
fun showConfirmation(context: Context, title: String, message: String, ok: Runnable?, cancel: Runnable? = null) {
|
||||||
val titleLayout = LayoutInflater.from(context).inflate(R.layout.dialog_alert_custom, null)
|
AlertDialogHelper.Builder(context)
|
||||||
(titleLayout.findViewById<View>(R.id.alertdialog_title) as TextView).text = title
|
|
||||||
(titleLayout.findViewById<View>(R.id.alertdialog_icon) as ImageView).setImageResource(R.drawable.ic_check_while_48dp)
|
|
||||||
AlertDialog.Builder(ContextThemeWrapper(context, R.style.AppTheme))
|
|
||||||
.setMessage(message)
|
.setMessage(message)
|
||||||
.setCustomTitle(titleLayout)
|
.setCustomTitle(AlertDialogHelper.buildCustomTitle(context, title))
|
||||||
.setPositiveButton(android.R.string.ok) { dialog: DialogInterface, _: Int ->
|
.setPositiveButton(android.R.string.ok) { dialog: DialogInterface, _: Int ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
SystemClock.sleep(100)
|
SystemClock.sleep(100)
|
||||||
|
@ -187,12 +159,9 @@ object OKDialog {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun showConfirmation(context: Context, title: String, message: String, ok: DialogInterface.OnClickListener?, cancel: DialogInterface.OnClickListener? = null) {
|
fun showConfirmation(context: Context, title: String, message: String, ok: DialogInterface.OnClickListener?, cancel: DialogInterface.OnClickListener? = null) {
|
||||||
val titleLayout = LayoutInflater.from(context).inflate(R.layout.dialog_alert_custom, null)
|
AlertDialogHelper.Builder(context)
|
||||||
(titleLayout.findViewById<View>(R.id.alertdialog_title) as TextView).text = title
|
|
||||||
(titleLayout.findViewById<View>(R.id.alertdialog_icon) as ImageView).setImageResource(R.drawable.ic_check_while_48dp)
|
|
||||||
AlertDialog.Builder(ContextThemeWrapper(context, R.style.AppTheme))
|
|
||||||
.setMessage(message)
|
.setMessage(message)
|
||||||
.setCustomTitle(titleLayout)
|
.setCustomTitle(AlertDialogHelper.buildCustomTitle(context, title))
|
||||||
.setPositiveButton(android.R.string.ok) { dialog: DialogInterface, which: Int ->
|
.setPositiveButton(android.R.string.ok) { dialog: DialogInterface, which: Int ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
SystemClock.sleep(100)
|
SystemClock.sleep(100)
|
||||||
|
|
|
@ -1,26 +1,94 @@
|
||||||
package info.nightscout.androidaps.utils;
|
package info.nightscout.androidaps.utils;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.media.MediaPlayer;
|
import android.media.MediaPlayer;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes;
|
||||||
|
import androidx.appcompat.view.ContextThemeWrapper;
|
||||||
|
|
||||||
import info.nightscout.androidaps.MainApp;
|
import info.nightscout.androidaps.MainApp;
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
import info.nightscout.androidaps.R;
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
|
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
||||||
|
|
||||||
|
|
||||||
public class ToastUtils {
|
public class ToastUtils {
|
||||||
|
|
||||||
|
public static class Long {
|
||||||
|
|
||||||
|
public static void warnToast(final Context ctx, final String string) {
|
||||||
|
graphicalToast(ctx, string, R.drawable.ic_toast_warn, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void infoToast(final Context ctx, final String string) {
|
||||||
|
graphicalToast(ctx, string, R.drawable.ic_toast_info,false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void okToast(final Context ctx, final String string) {
|
||||||
|
graphicalToast(ctx, string, R.drawable.ic_toast_check,false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void errorToast(final Context ctx, final String string) {
|
||||||
|
graphicalToast(ctx, string, R.drawable.ic_toast_error,false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void showToastInUiThread(final Context ctx, final int stringId) {
|
public static void showToastInUiThread(final Context ctx, final int stringId) {
|
||||||
showToastInUiThread(ctx, MainApp.gs(stringId));
|
showToastInUiThread(ctx, MainApp.gs(stringId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void warnToast(final Context ctx, final String string) {
|
||||||
|
graphicalToast(ctx, string, R.drawable.ic_toast_warn, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void infoToast(final Context ctx, final String string) {
|
||||||
|
graphicalToast(ctx, string, R.drawable.ic_toast_info, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void okToast(final Context ctx, final String string) {
|
||||||
|
graphicalToast(ctx, string, R.drawable.ic_toast_check, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void errorToast(final Context ctx, final String string) {
|
||||||
|
graphicalToast(ctx, string, R.drawable.ic_toast_error, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void graphicalToast(final Context ctx, final String string, @DrawableRes int iconId) {
|
||||||
|
graphicalToast(ctx, string, iconId, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("InflateParams")
|
||||||
|
public static void graphicalToast(final Context ctx, final String string, @DrawableRes int iconId, boolean isShort) {
|
||||||
|
Handler mainThread = new Handler(Looper.getMainLooper());
|
||||||
|
mainThread.post(() -> {
|
||||||
|
View toastRoot =LayoutInflater.from(new ContextThemeWrapper(ctx, R.style.AppTheme)).inflate(R.layout.toast, null);
|
||||||
|
TextView toastMessage = toastRoot.findViewById(android.R.id.message);
|
||||||
|
toastMessage.setText(string);
|
||||||
|
|
||||||
|
ImageView toastIcon = toastRoot.findViewById(android.R.id.icon);
|
||||||
|
toastIcon.setImageResource(iconId);
|
||||||
|
|
||||||
|
Toast toast = new Toast(ctx);
|
||||||
|
toast.setDuration(isShort ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG);
|
||||||
|
toast.setView(toastRoot);
|
||||||
|
toast.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static void showToastInUiThread(final Context ctx, final String string) {
|
public static void showToastInUiThread(final Context ctx, final String string) {
|
||||||
Handler mainThread = new Handler(Looper.getMainLooper());
|
Handler mainThread = new Handler(Looper.getMainLooper());
|
||||||
mainThread.post(() -> Toast.makeText(ctx, string, Toast.LENGTH_SHORT).show());
|
mainThread.post(() -> {
|
||||||
|
Toast.makeText(ctx, string, Toast.LENGTH_SHORT).show();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void showToastInUiThread(final Context ctx, final RxBusWrapper rxBus,
|
public static void showToastInUiThread(final Context ctx, final RxBusWrapper rxBus,
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package info.nightscout.androidaps.utils
|
package info.nightscout.androidaps.utils
|
||||||
|
|
||||||
|
import android.os.Handler
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import info.nightscout.androidaps.MainApp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by adrian on 2019-12-20.
|
* Created by adrian on 2019-12-20.
|
||||||
|
@ -8,3 +10,7 @@ import android.view.View
|
||||||
|
|
||||||
fun Boolean.toVisibility() = if (this) View.VISIBLE else View.GONE
|
fun Boolean.toVisibility() = if (this) View.VISIBLE else View.GONE
|
||||||
|
|
||||||
|
fun runOnUiThread(theRunnable: Runnable?) {
|
||||||
|
val mainHandler = Handler(MainApp.instance().applicationContext.mainLooper)
|
||||||
|
theRunnable?.let { mainHandler.post(it) }
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue