Merge pull request #1749 from MilosKozak/update-checker

Update checker
This commit is contained in:
Milos Kozak 2019-04-18 22:26:18 +02:00 committed by GitHub
commit 715a59bfba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 442 additions and 139 deletions

View file

@ -10,6 +10,8 @@ buildscript {
} }
} }
apply plugin: "com.android.application" apply plugin: "com.android.application"
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-android'
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'
apply plugin: "io.fabric" apply plugin: "io.fabric"
apply plugin: "jacoco-android" apply plugin: "jacoco-android"
@ -27,6 +29,7 @@ ext {
repositories { repositories {
maven { url 'https://maven.fabric.io/public' } maven { url 'https://maven.fabric.io/public' }
jcenter { url "https://jcenter.bintray.com/" } jcenter { url "https://jcenter.bintray.com/" }
mavenCentral()
} }
def generateGitBuild = { -> def generateGitBuild = { ->
@ -92,6 +95,9 @@ android {
moduleName "BleCommandUtil" moduleName "BleCommandUtil"
} }
} }
kotlinOptions {
jvmTarget = '1.8'
}
lintOptions { lintOptions {
// TODO remove once wear dependency com.google.android.gms:play-services-wearable:7.3.0 // 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 // has been upgraded (requiring significant code changes), which currently fails release
@ -249,6 +255,7 @@ dependencies {
androidTestImplementation "org.mockito:mockito-core:2.8.47" androidTestImplementation "org.mockito:mockito-core:2.8.47"
androidTestImplementation "com.google.dexmaker:dexmaker:${dexmakerVersion}" androidTestImplementation "com.google.dexmaker:dexmaker:${dexmakerVersion}"
androidTestImplementation "com.google.dexmaker:dexmaker-mockito:${dexmakerVersion}" androidTestImplementation "com.google.dexmaker:dexmaker-mockito:${dexmakerVersion}"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
} }
task unzip(type: Copy) { task unzip(type: Copy) {

View file

@ -48,9 +48,12 @@ import info.nightscout.androidaps.events.EventFeatureRunning;
import info.nightscout.androidaps.events.EventPreferenceChange; import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRefreshGui; import info.nightscout.androidaps.events.EventRefreshGui;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus; import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus;
import info.nightscout.androidaps.plugins.general.versionChecker.VersionCheckerUtilsKt;
import info.nightscout.androidaps.setupwizard.SetupWizardActivity; import info.nightscout.androidaps.setupwizard.SetupWizardActivity;
import info.nightscout.androidaps.tabs.TabPageAdapter; import info.nightscout.androidaps.tabs.TabPageAdapter;
import info.nightscout.androidaps.utils.AndroidPermission; import info.nightscout.androidaps.utils.AndroidPermission;
@ -59,7 +62,6 @@ import info.nightscout.androidaps.utils.LocaleHelper;
import info.nightscout.androidaps.utils.OKDialog; import info.nightscout.androidaps.utils.OKDialog;
import info.nightscout.androidaps.utils.PasswordProtection; import info.nightscout.androidaps.utils.PasswordProtection;
import info.nightscout.androidaps.utils.SP; import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.VersionChecker;
public class MainActivity extends AppCompatActivity { public class MainActivity extends AppCompatActivity {
private static Logger log = LoggerFactory.getLogger(L.CORE); private static Logger log = LoggerFactory.getLogger(L.CORE);
@ -115,7 +117,11 @@ public class MainActivity extends AppCompatActivity {
public void onPageScrollStateChanged(int state) { public void onPageScrollStateChanged(int state) {
} }
}); });
VersionChecker.check();
//Check here if loop plugin is disabled. Else check via constraints
if (!LoopPlugin.getPlugin().isEnabled(PluginType.LOOP))
VersionCheckerUtilsKt.checkVersion();
FabricPrivacy.setUserStats(); FabricPrivacy.setUserStats();
} }

View file

@ -50,6 +50,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.receivers.DBAccessRec
import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin; import info.nightscout.androidaps.plugins.general.overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.general.persistentNotification.PersistentNotificationPlugin; import info.nightscout.androidaps.plugins.general.persistentNotification.PersistentNotificationPlugin;
import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin; import info.nightscout.androidaps.plugins.general.smsCommunicator.SmsCommunicatorPlugin;
import info.nightscout.androidaps.plugins.general.versionChecker.VersionCheckerPlugin;
import info.nightscout.androidaps.plugins.general.wear.WearPlugin; import info.nightscout.androidaps.plugins.general.wear.WearPlugin;
import info.nightscout.androidaps.plugins.general.xdripStatusline.StatuslinePlugin; import info.nightscout.androidaps.plugins.general.xdripStatusline.StatuslinePlugin;
import info.nightscout.androidaps.plugins.insulin.InsulinOrefFreePeakPlugin; import info.nightscout.androidaps.plugins.insulin.InsulinOrefFreePeakPlugin;
@ -119,7 +120,7 @@ public class MainApp extends Application {
log.debug("onCreate"); log.debug("onCreate");
sInstance = this; sInstance = this;
sResources = getResources(); sResources = getResources();
sConstraintsChecker = new ConstraintChecker(this); sConstraintsChecker = new ConstraintChecker();
sDatabaseHelper = OpenHelperManager.getHelper(sInstance, DatabaseHelper.class); sDatabaseHelper = OpenHelperManager.getHelper(sInstance, DatabaseHelper.class);
try { try {
@ -179,6 +180,7 @@ public class MainApp extends Application {
if (Config.OTHERPROFILES) pluginsList.add(LocalProfilePlugin.getPlugin()); if (Config.OTHERPROFILES) pluginsList.add(LocalProfilePlugin.getPlugin());
pluginsList.add(TreatmentsPlugin.getPlugin()); pluginsList.add(TreatmentsPlugin.getPlugin());
if (Config.SAFETY) pluginsList.add(SafetyPlugin.getPlugin()); if (Config.SAFETY) pluginsList.add(SafetyPlugin.getPlugin());
if (Config.SAFETY) pluginsList.add(VersionCheckerPlugin.INSTANCE);
if (Config.SAFETY) pluginsList.add(StorageConstraintPlugin.getPlugin()); if (Config.SAFETY) pluginsList.add(StorageConstraintPlugin.getPlugin());
if (Config.APS) pluginsList.add(ObjectivesPlugin.getPlugin()); if (Config.APS) pluginsList.add(ObjectivesPlugin.getPlugin());
pluginsList.add(SourceXdripPlugin.getPlugin()); pluginsList.add(SourceXdripPlugin.getPlugin());

View file

@ -1,7 +1,11 @@
package info.nightscout.androidaps.data; package info.nightscout.androidaps.data;
import android.support.annotation.NonNull;
import java.util.ArrayList; import java.util.ArrayList;
import javax.annotation.Nonnull;
import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.interfaces.Constraint; import info.nightscout.androidaps.interfaces.Constraint;
@ -15,13 +19,6 @@ import info.nightscout.androidaps.interfaces.PluginType;
public class ConstraintChecker implements ConstraintsInterface { public class ConstraintChecker implements ConstraintsInterface {
private MainApp mainApp;
public ConstraintChecker(MainApp mainApp) {
this.mainApp = mainApp;
}
public Constraint<Boolean> isLoopInvokationAllowed() { public Constraint<Boolean> isLoopInvokationAllowed() {
return isLoopInvocationAllowed(new Constraint<>(true)); return isLoopInvocationAllowed(new Constraint<>(true));
} }
@ -79,9 +76,9 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Constraint<Boolean> isLoopInvocationAllowed(Constraint<Boolean> value) { public Constraint<Boolean> isLoopInvocationAllowed(@NonNull Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p; ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
@ -91,9 +88,9 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Constraint<Boolean> isClosedLoopAllowed(Constraint<Boolean> value) { public Constraint<Boolean> isClosedLoopAllowed(@NonNull Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p; ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
@ -103,9 +100,9 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Constraint<Boolean> isAutosensModeEnabled(Constraint<Boolean> value) { public Constraint<Boolean> isAutosensModeEnabled(@NonNull Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p; ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
@ -115,9 +112,9 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Constraint<Boolean> isAMAModeEnabled(Constraint<Boolean> value) { public Constraint<Boolean> isAMAModeEnabled(@NonNull Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p; ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
@ -127,9 +124,9 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Constraint<Boolean> isSMBModeEnabled(Constraint<Boolean> value) { public Constraint<Boolean> isSMBModeEnabled(@NonNull Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p; ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
@ -139,9 +136,9 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Constraint<Boolean> isUAMEnabled(Constraint<Boolean> value) { public Constraint<Boolean> isUAMEnabled(@NonNull Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p; ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
@ -151,8 +148,8 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) { public Constraint<Boolean> isAdvancedFilteringEnabled(@NonNull Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p; ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
@ -162,8 +159,8 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Constraint<Boolean> isSuperBolusEnabled(Constraint<Boolean> value) { public Constraint<Boolean> isSuperBolusEnabled(@NonNull Constraint<Boolean> value) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p; ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
@ -173,8 +170,8 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) { public Constraint<Double> applyBasalConstraints(@NonNull Constraint<Double> absoluteRate, Profile profile) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constraint = (ConstraintsInterface) p; ConstraintsInterface constraint = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
@ -184,8 +181,8 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, Profile profile) { public Constraint<Integer> applyBasalPercentConstraints(@NonNull Constraint<Integer> percentRate, Profile profile) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p; ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
@ -195,8 +192,8 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Constraint<Double> applyBolusConstraints(Constraint<Double> insulin) { public Constraint<Double> applyBolusConstraints(@NonNull Constraint<Double> insulin) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p; ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
@ -206,8 +203,8 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Constraint<Double> applyExtendedBolusConstraints(Constraint<Double> insulin) { public Constraint<Double> applyExtendedBolusConstraints(@NonNull Constraint<Double> insulin) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p; ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
@ -217,8 +214,8 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Constraint<Integer> applyCarbsConstraints(Constraint<Integer> carbs) { public Constraint<Integer> applyCarbsConstraints(@NonNull Constraint<Integer> carbs) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p; ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
@ -228,8 +225,8 @@ public class ConstraintChecker implements ConstraintsInterface {
} }
@Override @Override
public Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) { public Constraint<Double> applyMaxIOBConstraints(@NonNull Constraint<Double> maxIob) {
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class); ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
for (PluginBase p : constraintsPlugins) { for (PluginBase p : constraintsPlugins) {
ConstraintsInterface constrain = (ConstraintsInterface) p; ConstraintsInterface constrain = (ConstraintsInterface) p;
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue; if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;

View file

@ -74,6 +74,7 @@ public class Notification {
public static final int DST_LOOP_DISABLED = 49; public static final int DST_LOOP_DISABLED = 49;
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 int id; public int id;

View file

@ -0,0 +1,79 @@
package info.nightscout.androidaps.plugins.general.versionChecker
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.*
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.utils.SP
import java.util.concurrent.TimeUnit
/**
* Usually we would have a class here.
* Instead of having a class we can use an object directly inherited from PluginBase.
* This is a lazy loading singleton only loaded when actually used.
* */
object VersionCheckerPlugin : PluginBase(PluginDescription()
.mainType(PluginType.CONSTRAINTS)
.neverVisible(true)
.alwaysEnabled(true)
.showInList(false)
.pluginName(R.string.versionChecker)), ConstraintsInterface {
override fun isClosedLoopAllowed(value: Constraint<Boolean>): Constraint<Boolean> {
checkWarning()
checkUpdate()
return if (isOldVersion(GRACE_PERIOD_VERY_OLD))
value.set(false, MainApp.gs(R.string.very_old_version), this)
else
value
}
private fun checkWarning() {
val now = System.currentTimeMillis()
if (isOldVersion(GRACE_PERIOD_WARNING) && shouldWarnAgain(now)) {
// store last notification time
SP.putLong(R.string.key_last_versionchecker_warning, now)
//notify
val message = MainApp.gs(R.string.new_version_warning, Math.round(now / TimeUnit.DAYS.toMillis(1).toDouble()))
val notification = Notification(Notification.OLDVERSION, message, Notification.NORMAL)
MainApp.bus().post(EventNewNotification(notification))
}
}
private fun checkUpdate() {
val now = System.currentTimeMillis()
if (shouldCheckVersionAgain(now)) {
// store last notification time
SP.putLong(R.string.key_last_versioncheck, now)
checkVersion()
}
}
private fun shouldCheckVersionAgain(now: Long) =
now > SP.getLong(R.string.key_last_versioncheck, 0) + CHECK_EVERY
private fun shouldWarnAgain(now: Long) =
now > SP.getLong(R.string.key_last_versionchecker_warning, 0) + WARN_EVERY
override fun applyMaxIOBConstraints(maxIob: Constraint<Double>): Constraint<Double> =
if (isOldVersion(GRACE_PERIOD_OLD))
maxIob.set(0.toDouble(), MainApp.gs(R.string.old_version), this)
else
maxIob
private fun isOldVersion(gracePeriod: Long): Boolean {
val now = System.currentTimeMillis()
return now > SP.getLong(R.string.key_new_version_available_since, 0) + gracePeriod
}
val CHECK_EVERY = TimeUnit.DAYS.toMillis(1)
val WARN_EVERY = TimeUnit.DAYS.toMillis(1)
val GRACE_PERIOD_WARNING = TimeUnit.DAYS.toMillis(30)
val GRACE_PERIOD_OLD = TimeUnit.DAYS.toMillis(60)
val GRACE_PERIOD_VERY_OLD = TimeUnit.DAYS.toMillis(90)
}

View file

@ -0,0 +1,84 @@
package info.nightscout.androidaps.plugins.general.versionChecker
import android.content.Context
import android.net.ConnectivityManager
import info.nightscout.androidaps.BuildConfig
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.logging.L
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.utils.SP
import org.apache.http.HttpResponse
import org.apache.http.client.methods.HttpGet
import org.apache.http.impl.client.DefaultHttpClient
import org.slf4j.LoggerFactory
import java.io.IOException
import java.io.InputStream
// check network connection
fun isConnected(): Boolean {
val connMgr = MainApp.instance().applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
return connMgr.activeNetworkInfo?.isConnected ?: false
}
// convert inputstream to String
@Throws(IOException::class)
inline fun InputStream.findVersion(): String? {
val regex = "(.*)version(.*)\"(((\\d+)\\.)+(\\d+))\"(.*)".toRegex()
return bufferedReader()
.readLines()
.filter { regex.matches(it) }
.mapNotNull { regex.matchEntire(it)?.groupValues?.getOrNull(3) }
.firstOrNull()
}
private val log = LoggerFactory.getLogger(L.CORE)
@Suppress("DEPRECATION")
fun checkVersion() = if (isConnected()) {
Thread {
try {
val request = HttpGet("https://raw.githubusercontent.com/MilosKozak/AndroidAPS/master/app/build.gradle")
val response: HttpResponse = DefaultHttpClient().execute(request)
val version: String? = response.entity.content?.findVersion()
compareWithCurrentVersion(version, BuildConfig.VERSION_NAME)
} catch (e: IOException) {
log.debug("Github master version check error: $e")
}
}.start()
} else
log.debug("Github master version no checked. No connectivity")
fun compareWithCurrentVersion(newVersion: String?, currentVersion: String) {
val comparison: Int? = newVersion?.versionStrip()?.compareTo(currentVersion.versionStrip())
when {
comparison == null -> onVersionNotDetectable()
comparison == 0 -> onSameVersionDetected()
comparison > 0 -> onNewVersionDetected(currentVersion = currentVersion, newVersion = newVersion)
else -> log.debug("Version newer than master. Are you developer?")
}
}
fun onSameVersionDetected() {
SP.remove(R.string.key_new_version_available_since)
}
fun onVersionNotDetectable() {
log.debug("fetch failed, ignore and smartcast to non-null")
}
fun onNewVersionDetected(currentVersion: String, newVersion: String?) {
log.debug("Version ${currentVersion} outdated. Found $newVersion")
val notification = Notification(Notification.NEWVERSIONDETECTED, String.format(MainApp.gs(R.string.versionavailable), newVersion.toString()), Notification.LOW)
MainApp.bus().post(EventNewNotification(notification))
SP.putLong(R.string.key_new_version_available_since, System.currentTimeMillis())
}
fun String.versionStrip() = this.mapNotNull {
when (it) {
in '0'..'9' -> it
'.' -> it
else -> null
}
}.joinToString(separator = "")

View file

@ -1,100 +0,0 @@
package info.nightscout.androidaps.utils;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
import static android.content.Context.CONNECTIVITY_SERVICE;
public class VersionChecker {
private static Logger log = LoggerFactory.getLogger(L.CORE);
public static void check() {
if (isConnected())
new Thread(() -> {
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet("https://raw.githubusercontent.com/MilosKozak/AndroidAPS/master/app/build.gradle");
HttpResponse response;
try {
response = client.execute(request);
InputStream inputStream = response.getEntity().getContent();
if (inputStream != null) {
String result = findLine(inputStream);
if (result != null) {
int compare = result.compareTo(BuildConfig.VERSION_NAME.replace("\"", ""));
if (compare == 0) {
log.debug("Version equal to master");
return;
} else if (compare > 0) {
log.debug("Version outdated. Found " + result);
Notification notification = new Notification(Notification.NEWVERSIONDETECTED, String.format(MainApp.gs(R.string.versionavailable), result), Notification.LOW);
MainApp.bus().post(new EventNewNotification(notification));
return;
} else {
log.debug("Version newer than master. Are you developer?");
return;
}
}
}
log.debug("Github master version not found");
} catch (IOException e) {
e.printStackTrace();
log.debug("Github master version check error");
}
}).start();
else
log.debug("Github master version no checked. No connectivity");
}
// convert inputstream to String
private static String findLine(InputStream inputStream) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
String regex = "(.*)version(.*)\"(((\\d+)\\.)+(\\d+))\"(.*)";
Pattern p = Pattern.compile(regex);
while ((line = bufferedReader.readLine()) != null) {
Matcher m = p.matcher(line);
if (m.matches()) {
log.debug("+++ " + line);
return m.group(3);
} else {
log.debug("--- " + line);
}
}
inputStream.close();
return null;
}
// check network connection
public static boolean isConnected() {
ConnectivityManager connMgr = (ConnectivityManager) MainApp.instance().getApplicationContext().getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
return networkInfo != null && networkInfo.isConnected();
}
}

View file

@ -1326,6 +1326,15 @@
<string name="sms_wrongcode">Wrong code. Command cancelled.</string> <string name="sms_wrongcode">Wrong code. Command cancelled.</string>
<string name="notconfigured">Not configured</string> <string name="notconfigured">Not configured</string>
<string name="profileswitchcreated">Profile switch created</string> <string name="profileswitchcreated">Profile switch created</string>
<string name="versionChecker">Version Checker</string>
<string name="key_new_version_available_since" translatable="false">new_version_available_since</string>
<string name="key_last_versionchecker_warning" translatable="false">last_versionchecker_waring</string>
<string name="key_last_versioncheck" translatable="false">key_last_versioncheck</string>
<string name="old_version">old version</string>
<string name="very_old_version">very old version</string>
<string name="new_version_warning">New version for at least %1$d days available! Fallback to LGS after 60 days, loop will be disabled after 90 days</string>
<plurals name="objective_days"> <plurals name="objective_days">
<item quantity="one">%1$d day</item> <item quantity="one">%1$d day</item>
<item quantity="other">%1$d days</item> <item quantity="other">%1$d days</item>

View file

@ -289,7 +289,7 @@ public class ConstraintsCheckerTest {
//SafetyPlugin //SafetyPlugin
when(ConfigBuilderPlugin.getPlugin().getActivePump()).thenReturn(pump); when(ConfigBuilderPlugin.getPlugin().getActivePump()).thenReturn(pump);
constraintChecker = new ConstraintChecker(mainApp); constraintChecker = new ConstraintChecker();
safetyPlugin = SafetyPlugin.getPlugin(); safetyPlugin = SafetyPlugin.getPlugin();
objectivesPlugin = ObjectivesPlugin.getPlugin(); objectivesPlugin = ObjectivesPlugin.getPlugin();

View file

@ -0,0 +1,216 @@
package info.nightscout.androidaps.plugins.general.versionChecker
import com.squareup.otto.Bus
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.logging.L
import info.nightscout.androidaps.utils.SP
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers
import org.mockito.Mockito.*
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
@RunWith(PowerMockRunner::class)
class VersionCheckerUtilsKtTest {
@Test
fun findVersionMatchesRegularVersion() {
val buildGradle = """blabla
| android {
| aosenuthoae
| }
| version = "2.2.2"
| appName = "Aaoeu"
""".trimMargin()
val detectedVersion: String? = buildGradle.byteInputStream().findVersion()
assertEquals("2.2.2", detectedVersion)
}
// In case we merge a "x.x.x-dev" into master, don't see it as update.
@Test
fun `should return null on non-digit versions on master`() {
val buildGradle = """blabla
| android {
| aosenuthoae
| }
| version = "2.2.2-nefarious-underground-mod"
| appName = "Aaoeu"
""".trimMargin()
val detectedVersion: String? = buildGradle.byteInputStream().findVersion()
assertEquals(null, detectedVersion)
}
@Test
fun findVersionMatchesDoesNotMatchErrorResponse() {
val buildGradle = """<html><body>Balls! No build.gradle here. Move along</body><html>"""
val detectedVersion: String? = buildGradle.byteInputStream().findVersion()
assertEquals(null, detectedVersion)
}
@Test
fun testVersionStrip() {
assertEquals("2.2.2", "2.2.2".versionStrip())
assertEquals("2.2.2", "2.2.2-dev".versionStrip())
assertEquals("2.2.2", "2.2.2dev".versionStrip())
assertEquals("2.2.2", """"2.2.2"""".versionStrip())
}
@Test
@PrepareForTest(MainApp::class, L::class, SP::class)
fun `should find update1`() {
val bus = prepareBus()
compareWithCurrentVersion(newVersion = "2.2.3", currentVersion = "2.2.1")
verify(bus, times(1)).post(any())
PowerMockito.verifyStatic(SP::class.java, times(1))
SP.putLong(eq(R.string.key_new_version_available_since), ArgumentMatchers.anyLong())
PowerMockito.verifyNoMoreInteractions(SP::class.java)
}
@Test
@PrepareForTest(MainApp::class, L::class, SP::class)
fun `should find update2`() {
val bus = prepareBus()
compareWithCurrentVersion(newVersion = "2.2.3", currentVersion = "2.2.1-dev")
verify(bus, times(1)).post(any())
PowerMockito.verifyStatic(SP::class.java, times(1))
SP.putLong(eq(R.string.key_new_version_available_since), ArgumentMatchers.anyLong())
PowerMockito.verifyNoMoreInteractions(SP::class.java)
}
@Test
@PrepareForTest(MainApp::class, L::class, SP::class)
fun `should find update3`() {
val bus = prepareBus()
compareWithCurrentVersion(newVersion = "2.2.3", currentVersion = "2.1")
verify(bus, times(1)).post(any())
PowerMockito.verifyStatic(SP::class.java, times(1))
SP.putLong(eq(R.string.key_new_version_available_since), ArgumentMatchers.anyLong())
PowerMockito.verifyNoMoreInteractions(SP::class.java)
}
@Test
@PrepareForTest(MainApp::class, L::class, SP::class)
fun `should find update4`() {
val bus = prepareBus()
compareWithCurrentVersion(newVersion = "2.2", currentVersion = "2.1.1")
verify(bus, times(1)).post(any())
PowerMockito.verifyStatic(SP::class.java, times(1))
SP.putLong(eq(R.string.key_new_version_available_since), ArgumentMatchers.anyLong())
PowerMockito.verifyNoMoreInteractions(SP::class.java)
}
@Test
@PrepareForTest(MainApp::class, L::class, SP::class)
fun `should find update5`() {
val bus = prepareBus()
compareWithCurrentVersion(newVersion = "2.2.1", currentVersion = "2.2-dev")
verify(bus, times(1)).post(any())
PowerMockito.verifyStatic(SP::class.java, times(1))
SP.putLong(eq(R.string.key_new_version_available_since), ArgumentMatchers.anyLong())
PowerMockito.verifyNoMoreInteractions(SP::class.java)
}
@Test
@PrepareForTest(MainApp::class, L::class, SP::class)
fun `should find update6`() {
val bus = prepareBus()
compareWithCurrentVersion(newVersion = "2.2.1", currentVersion = "2.2dev")
verify(bus, times(1)).post(any())
PowerMockito.verifyStatic(SP::class.java, times(1))
SP.putLong(eq(R.string.key_new_version_available_since), ArgumentMatchers.anyLong())
PowerMockito.verifyNoMoreInteractions(SP::class.java)
}
@Test
@PrepareForTest(MainApp::class, L::class, SP::class)
fun `find same version`() {
val buildGradle = """blabla
| android {
| aosenuthoae
| }
| version = "2.2.2"
| appName = "Aaoeu"
""".trimMargin()
val bus = prepareBus()
compareWithCurrentVersion(buildGradle.byteInputStream().findVersion(), currentVersion = "2.2.2")
verify(bus, times(0)).post(any())
PowerMockito.verifyStatic(SP::class.java, times(1))
SP.remove(eq(R.string.key_new_version_available_since))
PowerMockito.verifyNoMoreInteractions(SP::class.java)
}
@Test
@PrepareForTest(MainApp::class, L::class, SP::class)
fun `find higher version`() {
val buildGradle = """blabla
| android {
| aosenuthoae
| }
| version = "3.0"
| appName = "Aaoeu"
""".trimMargin()
val bus = prepareBus()
compareWithCurrentVersion(buildGradle.byteInputStream().findVersion(), currentVersion = "2.2.2")
verify(bus, times(1)).post(any())
PowerMockito.verifyStatic(SP::class.java, times(1))
SP.putLong(eq(R.string.key_new_version_available_since), ArgumentMatchers.anyLong())
PowerMockito.verifyNoMoreInteractions(SP::class.java)
}
@Test
@PrepareForTest(System::class)
fun `set time`() {
PowerMockito.spy(System::class.java)
PowerMockito.`when`(System.currentTimeMillis()).thenReturn(100L)
assertEquals(100L, System.currentTimeMillis())
}
private fun prepareBus(): Bus {
PowerMockito.mockStatic(MainApp::class.java)
val mainApp = mock<MainApp>(MainApp::class.java)
`when`(MainApp.instance()).thenReturn(mainApp)
val bus = mock(Bus::class.java)
`when`(MainApp.bus()).thenReturn(bus)
`when`(MainApp.gs(ArgumentMatchers.anyInt())).thenReturn("some dummy string")
prepareSP()
return bus
}
private fun prepareSP() {
PowerMockito.mockStatic(SP::class.java)
}
private fun prepareLogging() {
PowerMockito.mockStatic(L::class.java)
`when`(L.isEnabled(any())).thenReturn(true)
}
}

View file

@ -1,6 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.3.21'
repositories { repositories {
google() google()
jcenter() jcenter()
@ -16,6 +17,7 @@ buildscript {
// in the individual module build.gradle files // in the individual module build.gradle files
classpath 'com.jakewharton:butterknife-gradle-plugin:9.0.0-SNAPSHOT' classpath 'com.jakewharton:butterknife-gradle-plugin:9.0.0-SNAPSHOT'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }