commit
715a59bfba
|
@ -10,6 +10,8 @@ buildscript {
|
|||
}
|
||||
}
|
||||
apply plugin: "com.android.application"
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: "io.fabric"
|
||||
apply plugin: "jacoco-android"
|
||||
|
@ -27,6 +29,7 @@ ext {
|
|||
repositories {
|
||||
maven { url 'https://maven.fabric.io/public' }
|
||||
jcenter { url "https://jcenter.bintray.com/" }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
def generateGitBuild = { ->
|
||||
|
@ -92,6 +95,9 @@ android {
|
|||
moduleName "BleCommandUtil"
|
||||
}
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
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
|
||||
|
@ -249,6 +255,7 @@ dependencies {
|
|||
androidTestImplementation "org.mockito:mockito-core:2.8.47"
|
||||
androidTestImplementation "com.google.dexmaker:dexmaker:${dexmakerVersion}"
|
||||
androidTestImplementation "com.google.dexmaker:dexmaker-mockito:${dexmakerVersion}"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
}
|
||||
|
||||
task unzip(type: Copy) {
|
||||
|
|
|
@ -48,9 +48,12 @@ import info.nightscout.androidaps.events.EventFeatureRunning;
|
|||
import info.nightscout.androidaps.events.EventPreferenceChange;
|
||||
import info.nightscout.androidaps.events.EventRefreshGui;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
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.general.nsclient.data.NSSettingsStatus;
|
||||
import info.nightscout.androidaps.plugins.general.versionChecker.VersionCheckerUtilsKt;
|
||||
import info.nightscout.androidaps.setupwizard.SetupWizardActivity;
|
||||
import info.nightscout.androidaps.tabs.TabPageAdapter;
|
||||
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.PasswordProtection;
|
||||
import info.nightscout.androidaps.utils.SP;
|
||||
import info.nightscout.androidaps.utils.VersionChecker;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
private static Logger log = LoggerFactory.getLogger(L.CORE);
|
||||
|
@ -115,7 +117,11 @@ public class MainActivity extends AppCompatActivity {
|
|||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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.persistentNotification.PersistentNotificationPlugin;
|
||||
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.xdripStatusline.StatuslinePlugin;
|
||||
import info.nightscout.androidaps.plugins.insulin.InsulinOrefFreePeakPlugin;
|
||||
|
@ -119,7 +120,7 @@ public class MainApp extends Application {
|
|||
log.debug("onCreate");
|
||||
sInstance = this;
|
||||
sResources = getResources();
|
||||
sConstraintsChecker = new ConstraintChecker(this);
|
||||
sConstraintsChecker = new ConstraintChecker();
|
||||
sDatabaseHelper = OpenHelperManager.getHelper(sInstance, DatabaseHelper.class);
|
||||
|
||||
try {
|
||||
|
@ -179,6 +180,7 @@ public class MainApp extends Application {
|
|||
if (Config.OTHERPROFILES) pluginsList.add(LocalProfilePlugin.getPlugin());
|
||||
pluginsList.add(TreatmentsPlugin.getPlugin());
|
||||
if (Config.SAFETY) pluginsList.add(SafetyPlugin.getPlugin());
|
||||
if (Config.SAFETY) pluginsList.add(VersionCheckerPlugin.INSTANCE);
|
||||
if (Config.SAFETY) pluginsList.add(StorageConstraintPlugin.getPlugin());
|
||||
if (Config.APS) pluginsList.add(ObjectivesPlugin.getPlugin());
|
||||
pluginsList.add(SourceXdripPlugin.getPlugin());
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.interfaces.Constraint;
|
||||
|
@ -15,13 +19,6 @@ import info.nightscout.androidaps.interfaces.PluginType;
|
|||
|
||||
public class ConstraintChecker implements ConstraintsInterface {
|
||||
|
||||
private MainApp mainApp;
|
||||
|
||||
public ConstraintChecker(MainApp mainApp) {
|
||||
this.mainApp = mainApp;
|
||||
}
|
||||
|
||||
|
||||
public Constraint<Boolean> isLoopInvokationAllowed() {
|
||||
return isLoopInvocationAllowed(new Constraint<>(true));
|
||||
}
|
||||
|
@ -79,9 +76,9 @@ public class ConstraintChecker implements ConstraintsInterface {
|
|||
}
|
||||
|
||||
@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) {
|
||||
ConstraintsInterface constraint = (ConstraintsInterface) p;
|
||||
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
|
||||
|
@ -91,9 +88,9 @@ public class ConstraintChecker implements ConstraintsInterface {
|
|||
}
|
||||
|
||||
@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) {
|
||||
ConstraintsInterface constraint = (ConstraintsInterface) p;
|
||||
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
|
||||
|
@ -103,9 +100,9 @@ public class ConstraintChecker implements ConstraintsInterface {
|
|||
}
|
||||
|
||||
@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) {
|
||||
ConstraintsInterface constraint = (ConstraintsInterface) p;
|
||||
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
|
||||
|
@ -115,9 +112,9 @@ public class ConstraintChecker implements ConstraintsInterface {
|
|||
}
|
||||
|
||||
@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) {
|
||||
ConstraintsInterface constrain = (ConstraintsInterface) p;
|
||||
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
|
||||
|
@ -127,9 +124,9 @@ public class ConstraintChecker implements ConstraintsInterface {
|
|||
}
|
||||
|
||||
@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) {
|
||||
ConstraintsInterface constraint = (ConstraintsInterface) p;
|
||||
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
|
||||
|
@ -139,9 +136,9 @@ public class ConstraintChecker implements ConstraintsInterface {
|
|||
}
|
||||
|
||||
@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) {
|
||||
ConstraintsInterface constraint = (ConstraintsInterface) p;
|
||||
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
|
||||
|
@ -151,8 +148,8 @@ public class ConstraintChecker implements ConstraintsInterface {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Constraint<Boolean> isAdvancedFilteringEnabled(Constraint<Boolean> value) {
|
||||
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
public Constraint<Boolean> isAdvancedFilteringEnabled(@NonNull Constraint<Boolean> value) {
|
||||
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
for (PluginBase p : constraintsPlugins) {
|
||||
ConstraintsInterface constraint = (ConstraintsInterface) p;
|
||||
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
|
||||
|
@ -162,8 +159,8 @@ public class ConstraintChecker implements ConstraintsInterface {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Constraint<Boolean> isSuperBolusEnabled(Constraint<Boolean> value) {
|
||||
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
public Constraint<Boolean> isSuperBolusEnabled(@NonNull Constraint<Boolean> value) {
|
||||
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
for (PluginBase p : constraintsPlugins) {
|
||||
ConstraintsInterface constraint = (ConstraintsInterface) p;
|
||||
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
|
||||
|
@ -173,8 +170,8 @@ public class ConstraintChecker implements ConstraintsInterface {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Constraint<Double> applyBasalConstraints(Constraint<Double> absoluteRate, Profile profile) {
|
||||
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
public Constraint<Double> applyBasalConstraints(@NonNull Constraint<Double> absoluteRate, Profile profile) {
|
||||
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
for (PluginBase p : constraintsPlugins) {
|
||||
ConstraintsInterface constraint = (ConstraintsInterface) p;
|
||||
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
|
||||
|
@ -184,8 +181,8 @@ public class ConstraintChecker implements ConstraintsInterface {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Constraint<Integer> applyBasalPercentConstraints(Constraint<Integer> percentRate, Profile profile) {
|
||||
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
public Constraint<Integer> applyBasalPercentConstraints(@NonNull Constraint<Integer> percentRate, Profile profile) {
|
||||
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
for (PluginBase p : constraintsPlugins) {
|
||||
ConstraintsInterface constrain = (ConstraintsInterface) p;
|
||||
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
|
||||
|
@ -195,8 +192,8 @@ public class ConstraintChecker implements ConstraintsInterface {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Constraint<Double> applyBolusConstraints(Constraint<Double> insulin) {
|
||||
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
public Constraint<Double> applyBolusConstraints(@NonNull Constraint<Double> insulin) {
|
||||
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
for (PluginBase p : constraintsPlugins) {
|
||||
ConstraintsInterface constrain = (ConstraintsInterface) p;
|
||||
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
|
||||
|
@ -206,8 +203,8 @@ public class ConstraintChecker implements ConstraintsInterface {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Constraint<Double> applyExtendedBolusConstraints(Constraint<Double> insulin) {
|
||||
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
public Constraint<Double> applyExtendedBolusConstraints(@NonNull Constraint<Double> insulin) {
|
||||
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
for (PluginBase p : constraintsPlugins) {
|
||||
ConstraintsInterface constrain = (ConstraintsInterface) p;
|
||||
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
|
||||
|
@ -217,8 +214,8 @@ public class ConstraintChecker implements ConstraintsInterface {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Constraint<Integer> applyCarbsConstraints(Constraint<Integer> carbs) {
|
||||
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
public Constraint<Integer> applyCarbsConstraints(@NonNull Constraint<Integer> carbs) {
|
||||
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
for (PluginBase p : constraintsPlugins) {
|
||||
ConstraintsInterface constrain = (ConstraintsInterface) p;
|
||||
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
|
||||
|
@ -228,8 +225,8 @@ public class ConstraintChecker implements ConstraintsInterface {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Constraint<Double> applyMaxIOBConstraints(Constraint<Double> maxIob) {
|
||||
ArrayList<PluginBase> constraintsPlugins = mainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
public Constraint<Double> applyMaxIOBConstraints(@NonNull Constraint<Double> maxIob) {
|
||||
ArrayList<PluginBase> constraintsPlugins = MainApp.getSpecificPluginsListByInterface(ConstraintsInterface.class);
|
||||
for (PluginBase p : constraintsPlugins) {
|
||||
ConstraintsInterface constrain = (ConstraintsInterface) p;
|
||||
if (!p.isEnabled(PluginType.CONSTRAINTS)) continue;
|
||||
|
|
|
@ -74,6 +74,7 @@ public class Notification {
|
|||
public static final int DST_LOOP_DISABLED = 49;
|
||||
public static final int DST_IN_24H = 50;
|
||||
public static final int DISKFULL = 51;
|
||||
public static final int OLDVERSION = 52;
|
||||
|
||||
|
||||
public int id;
|
||||
|
|
|
@ -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)
|
||||
|
||||
}
|
|
@ -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 = "")
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -1326,6 +1326,15 @@
|
|||
<string name="sms_wrongcode">Wrong code. Command cancelled.</string>
|
||||
<string name="notconfigured">Not configured</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">
|
||||
<item quantity="one">%1$d day</item>
|
||||
<item quantity="other">%1$d days</item>
|
||||
|
|
|
@ -289,7 +289,7 @@ public class ConstraintsCheckerTest {
|
|||
//SafetyPlugin
|
||||
when(ConfigBuilderPlugin.getPlugin().getActivePump()).thenReturn(pump);
|
||||
|
||||
constraintChecker = new ConstraintChecker(mainApp);
|
||||
constraintChecker = new ConstraintChecker();
|
||||
|
||||
safetyPlugin = SafetyPlugin.getPlugin();
|
||||
objectivesPlugin = ObjectivesPlugin.getPlugin();
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.21'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
@ -16,6 +17,7 @@ buildscript {
|
|||
// in the individual module build.gradle files
|
||||
|
||||
classpath 'com.jakewharton:butterknife-gradle-plugin:9.0.0-SNAPSHOT'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue