Merge branch 'dev' into automation

This commit is contained in:
Milos Kozak 2019-04-21 10:39:24 +02:00 committed by GitHub
commit 5f32eea488
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 475 additions and 146 deletions

View file

@ -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
@ -253,6 +259,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) {

View file

@ -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();
}

View file

@ -51,6 +51,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;
@ -120,7 +121,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 {
@ -180,6 +181,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());

View file

@ -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;

View file

@ -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;

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

@ -9,6 +9,7 @@
<string name="nav_resetdb">Reinicializar base de dados</string>
<string name="reset_db_confirm">Quer realmente reiniciar a base de dados?</string>
<string name="nav_exit">Sair</string>
<string name="danar_useextended_title">Usar bólus prolongado de &gt;200%%</string>
<string name="danar_bt_name_title">Dispositivo Bluetooth DanaR</string>
<string name="ns_sync_use_absolute_title">Usar sempre valores absolutos de basal</string>
<string name="alert_dialog_storage_permission_text">Por favor, reinicie o seu telefone ou reinicie o AndroidAPS a partir das Configurações do Sistema \ncaso contrário, o AndroidAPS não terá registro (importante para controlar e verificar se os algoritmos estão a funcionar corretamente)!</string>
@ -313,6 +314,7 @@
<string name="overview_bolusprogress_stop">Parar</string>
<string name="overview_bolusprogress_stoppressed">STOP PRESSIONADO</string>
<string name="waitingforpump">À espera da bomba</string>
<string name="overview_bolusprogress_goingtodeliver">Vão ser administradas %1$.2fU</string>
<string name="objectives_0_objective">Configuração da visualização e monitoramento, e análise de rácios e basals</string>
<string name="objectives_0_gate">Verificar se a BG está disponível no Nightscout, e se os dados de insulina da bomba estão a ser carregados</string>
<string name="objectives_1_objective">A iniciar um open loop</string>
@ -335,11 +337,23 @@
<string name="smscommunicator_loopisdisabled">Loop desactivado</string>
<string name="smscommunicator_loopisenabled">Loop activado</string>
<string name="valuelimitedto">%1$.2f limitado a %2$.2f</string>
<string name="valueoutofrange">O valor %1$s está fora dos limites permitidos</string>
<string name="smscommunicator_remotecommandnotallowed">O comando remoto não é permitido</string>
<string name="smscommunicator_remotebolusnotallowed">O bólus remoto não está disponível. Tente novamente mais tarde.</string>
<string name="smscommunicator_basalreplywithcode">Para começar a basal %1$.2fU/h durante%2$d min responda com o código %3$s</string>
<string name="smscommunicator_profilereplywithcode">Para mudar o perfil para %1$s %2$d%% responda com o código %3$s</string>
<string name="smscommunicator_extendedreplywithcode">Para começar o bólus estendido %1$.2fU/h para %2$d min responda com o código %3$s</string>
<string name="smscommunicator_basalpctreplywithcode">Para começar a basal %1$d% U/h durante %2$d min responda com o código %3$s</string>
<string name="smscommunicator_suspendreplywithcode">Para suspender o loop por %1$d minutos resposta com código %2$s</string>
<string name="smscommunicator_tempbasalset">Basal temporária %1$.2fU/h para %2$d min iniciada com êxito</string>
<string name="smscommunicator_extendedset">Bólus estendido %1$.2fU/h para %2$d min iniciado com êxito</string>
<string name="smscommunicator_tempbasalset_percent">Basal temporária %1$d% U/h durante%2$d min iniciada com êxito</string>
<string name="smscommunicator_tempbasalfailed">Início basal temp falhou </string>
<string name="smscommunicator_extendedfailed">Falha ao iniciar o bólus estendido</string>
<string name="smscommunicator_basalstopreplywithcode">Para parar a basal temporária responda com o código %1$s</string>
<string name="smscommunicator_extendedstopreplywithcode">Para parar o bólus temporário responda com o código %1$s</string>
<string name="smscommunicator_tempbasalcanceled">Basal temp cancelada</string>
<string name="smscommunicator_extendedcanceled">Bólus estendido cancelado</string>
<string name="smscommunicator_tempbasalcancelfailed">Não foi possivel cancelar a basal temp</string>
<string name="smscommunicator_extendedcancelfailed">Falhou o cancelamento do bolus extendido</string>
<string name="smscommunicator_unknowncommand">Comando desconhecido ou resposta errada</string>
@ -450,6 +464,7 @@
<string name="profile">Perfil</string>
<string name="openapsama_max_daily_safety_multiplier_summary">Valor padrão: 3 Por segurança é o valor limite estabelecido por OpenAPS. O que faz é limitar a basal a x3 a basal mázima. Se necessário modificar este valor, por favor ter em conta que os dados apontam para que os limites de segurança sejam - 3 x max diario ou 4x valor actual (qual seja menor) como valores máximos.</string>
<string name="openapsama_current_basal_safety_multiplier_summary">Valor padrão: 4 Esta é a outra parte dos valores limites de segurança - 3 x max diário ou 4x valor actual - do OpenAPS. Isto define que não importa o valor da basal máxima definido na bomba, o valor máximo da basal temporária não pode ser maior que 4 x o valor da basal definida na bomba. O objectivo é evitar que sejam determinadas basais temporárias demasiado elevadas antes que se perceba como o algoritmo funciona. 4x é um valor que a maior parte das pessoas nunca necessitará de alterar pois o mais provável é necessitar de alterar outras definições para não necessitar de \"ultrapassar\" este limite de segurança.</string>
<string name="openapsama_autosens_max_summary">Valor predefinido: 1.2\n Este é um multiplicador para autosens (e em breve autotune) que coloca um limite máximo de 20%% aos rácios superiores e inferiores de autosens, o que por sua vez calcula o quão alto autosens pode ajustar a basal, quão pode baixar o Factor de Sensibilidade (FSI) e baixar o valor alvo de glicose no sangue.</string>
<string name="openapsama_autosens_min_summary">Valor padrão: 0.7\nO outro lado dos limites de segurança do autosens. Coloca um tecto no quão baixo autosens pode ajustar as basais, e quão alto pode ajustar os valores de ISF e valor alvo de glucose no sangue (BG).</string>
<string name="openapsama_autosens_adjusttargets">Autosens também ajusta os alvos</string>
<string name="openapsama_autosens_adjusttargets_summary">Valor padrão: true\nÉ usado para permitir que autosens possa ajustar os valores alvo de glucose no sangue (BG), além de ISF e basais.</string>
@ -462,6 +477,7 @@
<string name="error_phone_not_valid">Número de telefone não é válido</string>
<string name="smscommunicator_invalidphonennumber">SMS número de telefone inválido</string>
<string name="overview_calibration">Calibração</string>
<string name="send_calibration">Enviar calibração %1$.1f para o xDrip?</string>
<string name="xdripnotinstalled">xDrip+ não está instalado</string>
<string name="calibrationsent">Calibração enviada para o xDrip</string>
<string name="smscommunicator_calibrationsent">Calibração enviada. Recepção têm de estar activada no xDrip.</string>
@ -602,6 +618,7 @@
<string name="absorptionsettings_title">Configurações de absorção</string>
<string name="absorption_maxtime_title">Tempo máx. absorção refeição [h]</string>
<string name="absorption_maxtime_summary">Tempo em horas, espectável para que todos os hidratos de carbono da refeição sejam absorvidos</string>
<string name="danar_visualizeextendedaspercentage_title">Visualizar bólus prolongado como %%</string>
<string name="careportal_sensorage_label_short">SAGE</string>
<string name="careportal_insulinage_label_short">IAGE</string>
<string name="careportal_canulaage_label_short">CAGE</string>
@ -714,6 +731,8 @@
<string name="dexcomg5_xdripupload_title">Enviar dados Glic. para xDrip+</string>
<string name="dexcomg5_xdripupload_summary">Seleccionar 640g/Eversense como fonte no xDrip+</string>
<string name="nsclientbg">Glic NSCliente</string>
<string name="minimalbasalvaluereplaced">Valor da basal alterado para o valor mínimo suportado: %1$s</string>
<string name="maximumbasalvaluereplaced">Valor da basal alterado para o valor máximo suportado: %1$s</string>
<string name="overview_editquickwizard_usebg">Cálculos Glic</string>
<string name="overview_editquickwizard_usebolusiob">Cálculo de Bólus IOB</string>
<string name="overview_editquickwizard_usebasaliob">Cálculo de Basal IOB</string>
@ -731,6 +750,8 @@
<string name="closedmodeenabled">Modo fechado ativado</string>
<string name="maxiobset">IOB máxima definida correctamente</string>
<string name="hasbgdata">Glicemia disponivel desde a fonte selecionada</string>
<string name="basalprofilenotaligned">Valores das basais não definidos por horas: %1$s</string>
<string name="zerovalueinprofile">Perfil inválido: %1$s</string>
<string name="combo_programming_bolus">A programar a bomba para injectar o bolus</string>
<string name="combo_refresh">Actualizar</string>
<string name="combo_pump_state_label">Estado</string>
@ -1072,6 +1093,7 @@
<string name="log_operating_mode_changes">Alterações do modo de funcionamento de registo</string>
<string name="log_alerts">Alertas de registo</string>
<string name="enable_tbr_emulation">Ativar a emulação TBR</string>
<string name="enable_tbr_emulation_summary">Usar bólus prolongados em vez de basais temporárias para contornar o limite de 250%%</string>
<string name="disconnect_delay">Atraso de desconexão [s]</string>
<string name="serial_number">Número de série</string>
<string name="release_software_version">Lançar versão de software</string>
@ -1111,11 +1133,13 @@
<string name="short_status_tbr">Basal temporária: %1$d%% para %2$d / %3$d minutos</string>
<string name="short_status_extended">Estendido: %1$.2f / %2$.2f U por %3$d min</string>
<string name="short_status_multiwave">Multionda: %1$.2f / %2$.2f U por %3$d min</string>
<string name="short_status_tdd">TDD: %1$.2f</string>
<string name="short_status_reservoir">Reser:%1$.2fU</string>
<string name="short_status_battery">Bat.: %1$d%%</string>
<string name="max_recovery_duration">Duração máxima da recuperação [s]</string>
<string name="min_recovery_duration">Duração mínima da recuperação [s]</string>
<string name="recovery_duration">Duração da recuperação</string>
<string name="timeout_during_handshake">Tempo de operação excedido - reset bluetooth</string>
<string name="profile_total">== ∑ %1$s U</string>
<string name="profile_ins_units_per_hout">U/h</string>
<string name="profile_carbs_per_unit">g/U</string>
@ -1124,6 +1148,8 @@
<string name="dexcom_lognssensorchange_summary">Criar evento \"Mudança de Sensor\" automaticamente no NS aquando do início do sensor</string>
<string name="tomato">Tomato (MiaoMiao)</string>
<string name="tomato_short">Tomato</string>
<string name="dst_in_24h_warning">Horário de Verão em 24h ou menos</string>
<string name="dst_loop_disabled_warning">Horário de Verão a menos de 3 horas - Closed Loop desligado</string>
<string name="storage">restrição de armazenamento interno</string>
<string name="diskfull">Liberte pelo menos %1$d MB do armazenamento interno! Loop desativado!</string>
<string name="wrongformat">Formato incorrecto</string>

View file

@ -152,8 +152,8 @@
<string name="constraints_violation">Constraints violation</string>
<string name="treatmentdeliveryerror">Bolus delivery error</string>
<string name="tempbasaldeliveryerror">Tempbasal delivery error</string>
<string name="overview_newtempbasal_basalpercent">Basal value [%]</string>
<string name="overview_newtempbasal_percent_label">% (100% = current)</string>
<string name="overview_newtempbasal_basalpercent">Basal value [%%]</string>
<string name="overview_newtempbasal_percent_label">%% (100%% = current)</string>
<string name="setbasalquestion">Accept new temp basal:</string>
<string name="overview_treatment_label">Treatment</string>
<string name="overview_calculator_label">Calculator</string>
@ -276,7 +276,7 @@
<string name="danar_iob_label">Pump IOB</string>
<string name="danar_dailyunits">Daily units</string>
<string name="pump_lastbolus_label">Last bolus</string>
<string name="hoursago">%.1fh ago</string>
<string name="hoursago">%1$.1fh ago</string>
<string name="danar_invalidinput">Invalid input data</string>
<string name="danar_valuenotsetproperly">Value not set properly</string>
<string name="reloadprofile">Reload profile</string>
@ -582,7 +582,7 @@
<string name="patientage_summary">Please select patient age to setup safety limits</string>
<string name="key_i_understand" translatable="false">I_understand</string>
<string name="Glimp">Glimp</string>
<string name="needwhitelisting">%s needs battery optimalization whitelisting for proper performance</string>
<string name="needwhitelisting">%1$s needs battery optimalization whitelisting for proper performance</string>
<string name="loopsuspended">Loop suspended</string>
<string name="loopsuspendedfor">Suspended (%1$d m)</string>
<string name="loopsuperbolusfor">Superbolus (%1$d m)</string>
@ -626,9 +626,9 @@
<string name="key_statuslights_res_critical" translatable="false">key_statuslights_res_critical</string>
<string name="statuslights_res_critical">Threshold critical reservoir level [U]</string>
<string name="key_statuslights_bat_warning" translatable="false">key_statuslights_bat_warning</string>
<string name="statuslights_bat_warning">Threshold warning battery level [%]</string>
<string name="statuslights_bat_warning">Threshold warning battery level [%%]</string>
<string name="key_statuslights_bat_critical" translatable="false">key_statuslights_bat_critical</string>
<string name="statuslights_bat_critical">Threshold critical battery level [%]</string>
<string name="statuslights_bat_critical">Threshold critical battery level [%%]</string>
<string name="iob">IOB</string>
<string name="cob">COB</string>
<string name="virtualpump_firmware_label">Firmware</string>
@ -871,7 +871,7 @@
<string name="combo_pump_state_running">Running</string>
<string name="combo_pump_action_cancelling_tbr">Cancelling TBR</string>
<string name="combo_pump_action_setting_tbr">Setting TBR (%1$d%% / %2$d min)</string>
<string name="combo_pump_action_bolusing">Bolusing (%.1f U)</string>
<string name="combo_pump_action_bolusing">Bolusing (%1$.1f U)</string>
<string name="combo_pump_action_refreshing">Refreshing</string>
<string name="combo_pump_unsupported_operation">Requested operation not supported by pump</string>
<string name="combo_low_suspend_forced_notification">Unsafe usage: extended or multiwave boluses are active. Loop mode has been set to low-suspend only 6 hours. Only normal boluses are supported in loop mode</string>
@ -1380,6 +1380,15 @@
<string name="add_short">ADD</string>
<string name="copy_short">COPY</string>
<string name="addnew">Add new</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>

View file

@ -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();

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.
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"
}
}