Merge branch 'dev' into dev

This commit is contained in:
Roumen Georgiev 2018-06-01 12:02:41 +03:00 committed by GitHub
commit 9569fbf183
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 593 additions and 252 deletions

View file

@ -1,20 +1,15 @@
package info.nightscout.androidaps;
import android.Manifest;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
@ -52,24 +47,17 @@ import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.setupwizard.SetupWizardActivity;
import info.nightscout.androidaps.tabs.SlidingTabLayout;
import info.nightscout.androidaps.tabs.TabPageAdapter;
import info.nightscout.utils.AndroidPermission;
import info.nightscout.utils.ImportExportPrefs;
import info.nightscout.utils.LocaleHelper;
import info.nightscout.utils.LogDialog;
import info.nightscout.utils.OKDialog;
import info.nightscout.utils.PasswordProtection;
import info.nightscout.utils.SP;
import info.nightscout.utils.ToastUtils;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static Logger log = LoggerFactory.getLogger(MainActivity.class);
static final int CASE_STORAGE = 0x1;
static final int CASE_SMS = 0x2;
static final int CASE_LOCATION = 0x3;
private boolean askForSMS = false;
private boolean askForLocation = true;
ImageButton menuButton;
protected PowerManager.WakeLock mWakeLock;
@ -77,32 +65,49 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Config.logFunctionCalls)
log.debug("onCreate");
Iconify.with(new FontAwesomeModule());
LocaleHelper.onCreate(this, "en");
setContentView(R.layout.activity_main);
menuButton = (ImageButton) findViewById(R.id.overview_menuButton);
menuButton.setOnClickListener(this);
checkEula();
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
askForPermission(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE}, CASE_STORAGE);
}
askForBatteryOptimizationPermission();
onStatusEvent(new EventSetWakeLock(SP.getBoolean("lockscreen", false)));
doMigrations();
registerBus();
setUpTabs(false);
}
@Override
protected void onResume() {
super.onResume();
if (!SP.getBoolean(R.string.key_setupwizard_processed, false)) {
Intent intent = new Intent(this, SetupWizardActivity.class);
startActivity(intent);
} else {
checkEula();
}
if (Config.logFunctionCalls)
log.debug("onCreate");
AndroidPermission.notifyForStoragePermission(this);
AndroidPermission.notifyForBatteryOptimizationPermission(this);
AndroidPermission.notifyForLocationPermissions(this);
AndroidPermission.notifyForSMSPermissions(this);
onStatusEvent(new EventSetWakeLock(SP.getBoolean("lockscreen", false)));
MainApp.bus().post(new EventFeatureRunning(EventFeatureRunning.Feature.MAIN));
}
registerBus();
setUpTabs(false);
@Override
public void onDestroy() {
if (mWakeLock != null)
if (mWakeLock.isHeld())
mWakeLock.release();
super.onDestroy();
}
@Subscribe
@ -212,120 +217,22 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
}
}
//check for sms permission if enable in prefernces
@Subscribe
public void onStatusEvent(final EventPreferenceChange ev) {
if (ev.isChanged(R.string.key_smscommunicator_remotecommandsallowed)) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
synchronized (this) {
if (SP.getBoolean(R.string.key_smscommunicator_remotecommandsallowed, false)) {
setAskForSMS();
}
}
}
}
}
private synchronized void setAskForSMS() {
askForSMS = true;
}
@Override
protected void onResume() {
super.onResume();
askForSMSPermissions();
askForLocationPermissions();
MainApp.bus().post(new EventFeatureRunning(EventFeatureRunning.Feature.MAIN));
}
@Override
public void onDestroy() {
if (mWakeLock != null)
if (mWakeLock.isHeld())
mWakeLock.release();
super.onDestroy();
}
private void askForBatteryOptimizationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final String packageName = getPackageName();
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
log.debug("Requesting ignore battery optimization");
OKDialog.show(this, MainApp.gs(R.string.pleaseallowpermission), String.format(MainApp.gs(R.string.needwhitelisting), MainApp.gs(R.string.app_name)), new Runnable() {
@Override
public void run() {
try {
final Intent intent = new Intent();
// ignoring battery optimizations required for constant connection
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
} catch (ActivityNotFoundException e) {
final String msg = MainApp.gs(R.string.batteryoptimalizationerror);
ToastUtils.showToastInUiThread(getApplicationContext(), msg);
log.error(msg);
}
}
});
}
}
}
private synchronized void askForSMSPermissions() {
if (askForSMS) { //only when settings were changed an MainActivity resumes.
askForSMS = false;
if (SP.getBoolean(R.string.smscommunicator_remotecommandsallowed, false)) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
askForPermission(new String[]{Manifest.permission.RECEIVE_SMS,
Manifest.permission.SEND_SMS,
Manifest.permission.RECEIVE_MMS}, CASE_SMS);
}
}
}
}
private synchronized void askForLocationPermissions() {
if (askForLocation) { //only when settings were changed an MainActivity resumes.
askForLocation = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
askForPermission(new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION}, CASE_LOCATION);
}
}
}
private void askForPermission(String[] permission, Integer requestCode) {
boolean test = false;
for (int i = 0; i < permission.length; i++) {
test = test || (ContextCompat.checkSelfPermission(this, permission[i]) != PackageManager.PERMISSION_GRANTED);
}
if (test) {
ActivityCompat.requestPermissions(this, permission, requestCode);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (permissions.length != 0) {
if (ActivityCompat.checkSelfPermission(this, permissions[0]) == PackageManager.PERMISSION_GRANTED) {
switch (requestCode) {
case CASE_STORAGE:
case AndroidPermission.CASE_STORAGE:
//show dialog after permission is granted
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setMessage(R.string.alert_dialog_storage_permission_text);
alert.setPositiveButton(R.string.ok, null);
alert.show();
break;
case CASE_LOCATION:
case CASE_SMS:
case AndroidPermission.CASE_LOCATION:
case AndroidPermission.CASE_SMS:
case AndroidPermission.CASE_BATTERY:
break;
}
}
@ -426,7 +333,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
builder.setPositiveButton(MainApp.gs(R.string.ok), null);
AlertDialog alertDialog = builder.create();
alertDialog.show();
((TextView)alertDialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
((TextView) alertDialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
break;
case R.id.nav_exit:
log.debug("Exiting");

View file

@ -427,9 +427,7 @@ public class DataService extends IntentService {
if (bundles.containsKey("sgv")) {
String sgvstring = bundles.getString("sgv");
JSONObject sgvJson = new JSONObject(sgvstring);
NSSgv nsSgv = new NSSgv(sgvJson);
BgReading bgReading = new BgReading(nsSgv);
MainApp.getDbHelper().createIfNotExists(bgReading, "NS");
storeSgv(sgvJson);
}
if (bundles.containsKey("sgvs")) {
@ -437,9 +435,7 @@ public class DataService extends IntentService {
JSONArray jsonArray = new JSONArray(sgvstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject sgvJson = jsonArray.getJSONObject(i);
NSSgv nsSgv = new NSSgv(sgvJson);
BgReading bgReading = new BgReading(nsSgv);
MainApp.getDbHelper().createIfNotExists(bgReading, "NS");
storeSgv(sgvJson);
}
}
} catch (Exception e) {
@ -452,11 +448,7 @@ public class DataService extends IntentService {
if (bundles.containsKey("mbg")) {
String mbgstring = bundles.getString("mbg");
JSONObject mbgJson = new JSONObject(mbgstring);
NSMbg nsMbg = new NSMbg(mbgJson);
CareportalEvent careportalEvent = new CareportalEvent(nsMbg);
MainApp.getDbHelper().createOrUpdate(careportalEvent);
if (Config.logIncommingData)
log.debug("Adding/Updating new MBG: " + careportalEvent.log());
storeMbg(mbgJson);
}
if (bundles.containsKey("mbgs")) {
@ -464,11 +456,7 @@ public class DataService extends IntentService {
JSONArray jsonArray = new JSONArray(sgvstring);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject mbgJson = jsonArray.getJSONObject(i);
NSMbg nsMbg = new NSMbg(mbgJson);
CareportalEvent careportalEvent = new CareportalEvent(nsMbg);
MainApp.getDbHelper().createOrUpdate(careportalEvent);
if (Config.logIncommingData)
log.debug("Adding/Updating new MBG: " + careportalEvent.log());
storeMbg(mbgJson);
}
}
} catch (Exception e) {
@ -549,6 +537,20 @@ public class DataService extends IntentService {
}
}
private void storeMbg(JSONObject mbgJson) {
NSMbg nsMbg = new NSMbg(mbgJson);
CareportalEvent careportalEvent = new CareportalEvent(nsMbg);
MainApp.getDbHelper().createOrUpdate(careportalEvent);
if (Config.logIncommingData)
log.debug("Adding/Updating new MBG: " + careportalEvent.log());
}
private void storeSgv(JSONObject sgvJson) {
NSSgv nsSgv = new NSSgv(sgvJson);
BgReading bgReading = new BgReading(nsSgv);
MainApp.getDbHelper().createIfNotExists(bgReading, "NS");
}
private void handleNewSMS(Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle == null) return;

View file

@ -218,50 +218,19 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli
double iageUrgent = nsSettings.getExtendedWarnValue("iage", "urgent", 96);
double iageWarn = nsSettings.getExtendedWarnValue("iage", "warn", 72);
handleAge(iage, CareportalEvent.INSULINCHANGE, iageWarn, iageUrgent);
double cageUrgent = nsSettings.getExtendedWarnValue("cage", "urgent", 72);
double cageWarn = nsSettings.getExtendedWarnValue("cage", "warn", 48);
handleAge(sage, CareportalEvent.SITECHANGE, cageWarn, cageUrgent);
double sageUrgent = nsSettings.getExtendedWarnValue("sage", "urgent", 166);
double sageWarn = nsSettings.getExtendedWarnValue("sage", "warn", 164);
handleAge(sage, CareportalEvent.SENSORCHANGE, sageWarn, sageUrgent);
double pbageUrgent = nsSettings.getExtendedWarnValue("pgage", "urgent", 360);
double pbageWarn = nsSettings.getExtendedWarnValue("pgage", "warn", 240);
String notavailable = OverviewFragment.shorttextmode ? "-" : MainApp.gs(R.string.notavailable);
if (sage != null) {
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.SENSORCHANGE);
if (careportalEvent != null) {
sage.setTextColor(CareportalFragment.determineTextColor(careportalEvent, sageWarn, sageUrgent));
sage.setText(careportalEvent.age());
} else {
sage.setText(notavailable);
}
}
if (iage != null) {
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.INSULINCHANGE);
if (careportalEvent != null) {
iage.setTextColor(CareportalFragment.determineTextColor(careportalEvent, iageWarn, iageUrgent));
iage.setText(careportalEvent.age());
} else {
iage.setText(notavailable);
}
}
if (cage != null) {
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.SITECHANGE);
if (careportalEvent != null) {
cage.setTextColor(CareportalFragment.determineTextColor(careportalEvent, cageWarn, cageUrgent));
cage.setText(careportalEvent.age());
} else {
cage.setText(notavailable);
}
}
if (pbage != null) {
careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(CareportalEvent.PUMPBATTERYCHANGE);
if (careportalEvent != null) {
pbage.setTextColor(CareportalFragment.determineTextColor(careportalEvent, pbageWarn, pbageUrgent));
pbage.setText(careportalEvent.age());
} else {
pbage.setText(notavailable);
}
}
handleAge(pbage, CareportalEvent.PUMPBATTERYCHANGE, pbageWarn, pbageUrgent);
}
);
}
@ -277,5 +246,21 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli
}
}
private static TextView handleAge(final TextView age, String eventType, double warnThreshold, double urgentThreshold) {
String notavailable = OverviewFragment.shorttextmode ? "-" : MainApp.gs(R.string.notavailable);
if (age != null) {
CareportalEvent careportalEvent = MainApp.getDbHelper().getLastCareportalEvent(eventType);
if (careportalEvent != null) {
age.setTextColor(CareportalFragment.determineTextColor(careportalEvent, warnThreshold, urgentThreshold));
age.setText(careportalEvent.age());
} else {
age.setText(notavailable);
}
}
return age;
}
}

View file

@ -251,6 +251,7 @@ public class ObjectivesFragment extends SubscriberFragment {
ObjectivesPlugin.objectives.get(3).gate = MainApp.gs(R.string.objectives_3_gate);
ObjectivesPlugin.objectives.get(4).gate = MainApp.gs(R.string.objectives_4_gate);
ObjectivesPlugin.objectives.get(5).gate = MainApp.gs(R.string.objectives_5_gate);
ObjectivesPlugin.objectives.get(7).gate = MainApp.gs(R.string.objectives_7_gate);
updateGUI();

View file

@ -347,13 +347,12 @@ public class IobCobCalculatorPlugin extends PluginBase {
return null;
}
public BasalData getBasalData(long time) {
public BasalData getBasalData(Profile profile, long time) {
long now = System.currentTimeMillis();
time = roundUpTime(time);
BasalData retval = basalDataTable.get(time);
if (retval == null) {
retval = new BasalData();
Profile profile = MainApp.getConfigBuilder().getProfile(time);
TemporaryBasal tb = TreatmentsPlugin.getPlugin().getTempBasalFromHistory(time);
retval.basal = profile.getBasal(time);
if (tb != null) {

View file

@ -26,14 +26,24 @@ public class BroadcastStatus {
private static Logger log = LoggerFactory.getLogger(BroadcastStatus.class);
public static void handleNewStatus(NSSettingsStatus status, Context context, boolean isDelta) {
LocalBroadcastManager.getInstance(MainApp.instance())
.sendBroadcast(createIntent(status, isDelta));
if(SP.getBoolean(R.string.key_nsclient_localbroadcasts, true)) {
context.sendBroadcast(createIntent(status, isDelta));
}
}
private static Intent createIntent(NSSettingsStatus status, boolean isDelta) {
Bundle bundle = new Bundle();
try {
bundle.putString("nsclientversionname", MainApp.instance().getPackageManager().getPackageInfo(MainApp.instance().getPackageName(), 0).versionName);
bundle.putInt("nsclientversioncode", MainApp.instance().getPackageManager().getPackageInfo(MainApp.instance().getPackageName(), 0).versionCode);
} catch (PackageManager.NameNotFoundException e) {
log.error("Unhandled exception", e);
}
bundle.putString("nightscoutversionname", NSClientService.nightscoutVersionName);
bundle.putInt("nightscoutversioncode", NSClientService.nightscoutVersionCode);
bundle.putString("status", status.getData().toString());
@ -41,24 +51,7 @@ public class BroadcastStatus {
Intent intent = new Intent(Intents.ACTION_NEW_STATUS);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
LocalBroadcastManager.getInstance(MainApp.instance()).sendBroadcast(intent);
if(SP.getBoolean(R.string.key_nsclient_localbroadcasts, true)) {
bundle = new Bundle();
try {
bundle.putString("nsclientversionname", MainApp.instance().getPackageManager().getPackageInfo(MainApp.instance().getPackageName(), 0).versionName);
bundle.putInt("nsclientversioncode", MainApp.instance().getPackageManager().getPackageInfo(MainApp.instance().getPackageName(), 0).versionCode);
} catch (PackageManager.NameNotFoundException e) {
log.error("Unhandled exception", e);
}
bundle.putString("nightscoutversionname", NSClientService.nightscoutVersionName);
bundle.putInt("nightscoutversioncode", NSClientService.nightscoutVersionCode);
bundle.putString("status", status.getData().toString());
bundle.putBoolean("delta", isDelta);
intent = new Intent(Intents.ACTION_NEW_STATUS);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
context.sendBroadcast(intent);
}
return intent;
}
}

View file

@ -250,7 +250,7 @@ public class DetermineBasalAdapterSMBJS {
mProfile.put("min_5m_carbimpact", SP.getDouble(R.string.key_openapsama_min_5m_carbimpact, SMBDefaults.min_5m_carbimpact));
}
mProfile.put("remainingCarbsCap", SMBDefaults.remainingCarbsCap);
mProfile.put("enableUAM", SP.getBoolean(R.string.key_use_uam, false)&& advancedFiltering);
mProfile.put("enableUAM", SP.getBoolean(R.string.key_use_uam, false));
mProfile.put("A52_risk_enable", SMBDefaults.A52_risk_enable);
mProfile.put("enableSMB_with_COB", SP.getBoolean(R.string.key_enableSMB_with_COB, false));
mProfile.put("enableSMB_with_temptarget", SP.getBoolean(R.string.key_enableSMB_with_temptarget, false));

View file

@ -981,16 +981,19 @@ public class OverviewFragment extends Fragment implements View.OnClickListener,
if (timeView != null) { //must not exists
timeView.setText(DateUtil.timeString(new Date()));
}
updateNotifications();
pumpStatusLayout.setVisibility(View.GONE);
loopStatusLayout.setVisibility(View.GONE);
if (!MainApp.getConfigBuilder().isProfileValid("Overview")) {
pumpStatusView.setText(R.string.noprofileset);
pumpStatusLayout.setVisibility(View.VISIBLE);
loopStatusLayout.setVisibility(View.GONE);
return;
}
pumpStatusLayout.setVisibility(View.GONE);
loopStatusLayout.setVisibility(View.VISIBLE);
updateNotifications();
CareportalFragment.updateAge(getActivity(), sage, iage, cage, pbage);
BgReading actualBG = DatabaseHelper.actualBg();
BgReading lastBG = DatabaseHelper.lastBg();

View file

@ -136,7 +136,9 @@ public class GraphData {
double lastBaseBasal = 0;
double lastTempBasal = 0;
for (long time = fromTime; time < toTime; time += 60 * 1000L) {
BasalData basalData = IobCobCalculatorPlugin.getPlugin().getBasalData(time);
Profile profile = MainApp.getConfigBuilder().getProfile(time);
if (profile == null) continue;
BasalData basalData = IobCobCalculatorPlugin.getPlugin().getBasalData(profile, time);
double baseBasalValue = basalData.basal;
double absoluteLineValue = baseBasalValue;
double tempBasalValue = 0;

View file

@ -60,6 +60,10 @@ public class Notification {
public static final int PROFILE_SWITCH_MISSING = 32;
public static final int NOT_ENG_MODE_OR_RELEASE = 33;
public static final int WRONG_PUMP_PASSWORD = 34;
public static final int PERMISSION_STORAGE = 35;
public static final int PERMISSION_LOCATION = 36;
public static final int PERMISSION_BATTERY = 37;
public static final int PERMISSION_SMS = 38;
public int id;

View file

@ -42,9 +42,12 @@ public class NotificationRecyclerViewAdapter extends RecyclerView.Adapter<Notifi
public void onBindViewHolder(NotificationsViewHolder holder, int position) {
Notification notification = notificationsList.get(position);
holder.dismiss.setTag(notification);
if (Objects.equals(notification.text, MainApp.gs(R.string.nsalarm_staledata)))
if (notification instanceof NotificationWithAction)
holder.dismiss.setText(((NotificationWithAction) notification).buttonText);
else if (Objects.equals(notification.text, MainApp.gs(R.string.nsalarm_staledata)))
holder.dismiss.setText("snooze");
holder.text.setText(notification.text+'\n');
holder.text.setText(notification.text + '\n');
holder.time.setText(DateUtil.timeString(notification.date));
if (notification.level == Notification.URGENT)
holder.cv.setBackgroundColor(ContextCompat.getColor(MainApp.instance(), R.color.notificationUrgent));
@ -100,6 +103,9 @@ public class NotificationRecyclerViewAdapter extends RecyclerView.Adapter<Notifi
log.debug("snooze nsalarm_staledatavalue in minutes is " + SP.getInt("nsalarm_staledatavalue", 15) + "\n in ms is: " + msToSnooze + " currentTimeMillis is: " + System.currentTimeMillis());
nstore.snoozeTo(System.currentTimeMillis() + (SP.getInt("nsalarm_staledatavalue", 15) * 60 * 1000L));
}
if (notification instanceof NotificationWithAction) {
((NotificationWithAction) notification).action.run();
}
break;
}
}

View file

@ -61,7 +61,7 @@ public class NotificationStore {
}
store.add(n);
if (SP.getBoolean(MainApp.gs(R.string.key_raise_notifications_as_android_notifications), false)) {
if (SP.getBoolean(MainApp.gs(R.string.key_raise_notifications_as_android_notifications), false) && !(n instanceof NotificationWithAction)) {
raiseSystemNotification(n);
if (usesChannels && n.soundId != null) {
Intent alarm = new Intent(MainApp.instance().getApplicationContext(), AlarmSoundService.class);

View file

@ -0,0 +1,16 @@
package info.nightscout.androidaps.plugins.Overview.notifications;
public class NotificationWithAction extends Notification {
Runnable action;
String buttonText;
public NotificationWithAction(int id, String text, int level) {
super(id, text, level);
}
public void action(String buttonText, Runnable action) {
this.buttonText = buttonText;
this.action = action;
}
}

View file

@ -32,6 +32,6 @@ public class SourceNSClientPlugin extends PluginBase implements BgSourceInterfac
@Override
public boolean advancedFilteringSupported() {
return true;
return false;
}
}

View file

@ -1,6 +1,13 @@
package info.nightscout.androidaps.setupwizard;
import android.Manifest;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.PowerManager;
import android.provider.Settings;
import android.support.v7.app.AppCompatActivity;
import com.squareup.otto.Subscribe;
@ -45,19 +52,24 @@ import info.nightscout.androidaps.setupwizard.elements.SWEditString;
import info.nightscout.androidaps.setupwizard.elements.SWEditUrl;
import info.nightscout.androidaps.setupwizard.events.EventSWLabel;
import info.nightscout.androidaps.setupwizard.events.EventSWUpdate;
import info.nightscout.utils.AndroidPermission;
import info.nightscout.utils.ImportExportPrefs;
import info.nightscout.utils.LocaleHelper;
import info.nightscout.utils.PasswordProtection;
import info.nightscout.utils.SP;
import info.nightscout.utils.ToastUtils;
public class SWDefinition {
private static Logger log = LoggerFactory.getLogger(SWDefinition.class);
private String packageName;
private AppCompatActivity activity;
private List<SWScreen> screens = new ArrayList<>();
public void setActivity(AppCompatActivity activity) {
this.activity = activity;
packageName = activity.getPackageName();
}
public AppCompatActivity getActivity() {
@ -99,6 +111,57 @@ public class SWDefinition {
return SP.contains(R.string.key_language);
})
)
.add(new SWScreen(R.string.end_user_license_agreement)
.skippable(false)
.add(new SWInfotext()
.label(R.string.end_user_license_agreement_text))
.add(new SWBreak())
.add(new SWButton()
.text(R.string.end_user_license_agreement_i_understand)
.visibility(() -> !SP.getBoolean(R.string.key_i_understand, false))
.action(() -> {
SP.putBoolean(R.string.key_i_understand, true);
MainApp.bus().post(new EventSWUpdate(false));
}))
.visibility(() -> !SP.getBoolean(R.string.key_i_understand, false))
.validator(() -> SP.getBoolean(R.string.key_i_understand, false))
)
.add(new SWScreen(R.string.permission)
.skippable(false)
.add(new SWInfotext()
.label(String.format(MainApp.gs(R.string.needwhitelisting), MainApp.gs(R.string.app_name))))
.add(new SWBreak())
.add(new SWButton()
.text(R.string.askforpermission)
.visibility(() -> Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS))
.action(() -> AndroidPermission.askForPermission(getActivity(), Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, AndroidPermission.CASE_BATTERY)))
.visibility(() -> Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS))
.validator(() -> !(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)))
)
.add(new SWScreen(R.string.permission)
.skippable(false)
.add(new SWInfotext()
.label(MainApp.gs(R.string.needlocationpermission)))
.add(new SWBreak())
.add(new SWButton()
.text(R.string.askforpermission)
.visibility(() -> Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION))
.action(() -> AndroidPermission.askForPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION, AndroidPermission.CASE_LOCATION)))
.visibility(() -> Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION))
.validator(() -> !(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)))
)
.add(new SWScreen(R.string.permission)
.skippable(false)
.add(new SWInfotext()
.label(MainApp.gs(R.string.needstoragepermission)))
.add(new SWBreak())
.add(new SWButton()
.text(R.string.askforpermission)
.visibility(() -> Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE))
.action(() -> AndroidPermission.askForPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE, AndroidPermission.CASE_STORAGE)))
.visibility(() -> Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE))
.validator(() -> !(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !AndroidPermission.checkForPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)))
)
.add(new SWScreen(R.string.nsclientinternal_title)
.skippable(true)
.add(new SWInfotext()
@ -154,11 +217,11 @@ public class SWDefinition {
.add(new SWScreen(R.string.configbuilder_insulin)
.skippable(false)
.add(new SWInfotext()
.label(MainApp.gs(R.string.fastactinginsulincomment) + " = " + MainApp.gs(R.string.rapid_acting_oref)))
.label(MainApp.gs(R.string.rapid_acting_oref) + ": " + MainApp.gs(R.string.fastactinginsulincomment)))
.add(new SWInfotext()
.label(MainApp.gs(R.string.ultrafastactinginsulincomment) + " = " + MainApp.gs(R.string.ultrarapid_oref)))
.label(MainApp.gs(R.string.ultrarapid_oref) + ": " + MainApp.gs(R.string.ultrafastactinginsulincomment)))
.add(new SWInfotext()
.label(MainApp.gs(R.string.free_peak_oref_description) + " = " + MainApp.gs(R.string.free_peak_oref)))
.label(MainApp.gs(R.string.free_peak_oref) + ": " + MainApp.gs(R.string.free_peak_oref_description)))
.add(new SWBreak())
.add(new SWInfotext()
.label(R.string.diawarning))
@ -166,6 +229,18 @@ public class SWDefinition {
.add(new SWPlugin()
.option(PluginType.INSULIN)
.label(R.string.configbuilder_insulin))
.add(new SWBreak())
.add(new SWButton()
.text(R.string.insulinsourcesetup)
.action(() -> {
final PluginBase plugin = (PluginBase) MainApp.getConfigBuilder().getActiveInsulin();
PasswordProtection.QueryPassword(activity, R.string.settings_password, "settings_password", () -> {
Intent i = new Intent(activity, PreferencesActivity.class);
i.putExtra("id", plugin.getPreferencesId());
activity.startActivity(i);
}, null);
})
.visibility(() -> MainApp.getConfigBuilder().getActiveInsulin()!= null && ((PluginBase) MainApp.getConfigBuilder().getActiveInsulin()).getPreferencesId() > 0))
.validator(() -> MainApp.getConfigBuilder().getActiveInsulin() != null)
)
.add(new SWScreen(R.string.configbuilder_bgsource)

View file

@ -1,10 +1,14 @@
package info.nightscout.androidaps.setupwizard;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import com.squareup.otto.Subscribe;
@ -24,6 +28,7 @@ import info.nightscout.androidaps.plugins.ConstraintsObjectives.events.EventObje
import info.nightscout.androidaps.plugins.NSClientInternal.events.EventNSClientStatus;
import info.nightscout.androidaps.setupwizard.elements.SWItem;
import info.nightscout.androidaps.setupwizard.events.EventSWUpdate;
import info.nightscout.utils.AndroidPermission;
import info.nightscout.utils.LocaleHelper;
import info.nightscout.utils.OKDialog;
import info.nightscout.utils.SP;
@ -32,6 +37,8 @@ public class SetupWizardActivity extends AppCompatActivity {
//logging
private static Logger log = LoggerFactory.getLogger(SetupWizardActivity.class);
ScrollView scrollView;
private SWDefinition swDefinition = new SWDefinition();
private List<SWScreen> screens = swDefinition.getScreens();
private int currentWizardPage = 0;
@ -43,6 +50,8 @@ public class SetupWizardActivity extends AppCompatActivity {
LocaleHelper.onCreate(this, "en");
setContentView(R.layout.activity_setupwizard);
scrollView = (ScrollView) findViewById(R.id.sw_scrollview);
Intent intent = getIntent();
currentWizardPage = intent.getIntExtra(SetupWizardActivity.INTENT_MESSAGE, 0);
if (screens.size() > 0 && currentWizardPage < screens.size()) {
@ -66,6 +75,7 @@ public class SetupWizardActivity extends AppCompatActivity {
}
public void exitPressed(View view) {
SP.putBoolean(R.string.key_setupwizard_processed, true);
OKDialog.showConfirmation(this, MainApp.gs(R.string.exitwizard), this::finish);
}
@ -121,6 +131,7 @@ public class SetupWizardActivity extends AppCompatActivity {
SWItem currentItem = currentScreen.items.get(i);
currentItem.generateDialog(this.findViewById(R.id.sw_content_fields), layout);
}
scrollView.smoothScrollTo(0,0);
}
private void updateButtons() {
@ -166,6 +177,7 @@ public class SetupWizardActivity extends AppCompatActivity {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
}
private int nextPage() {
@ -180,11 +192,35 @@ public class SetupWizardActivity extends AppCompatActivity {
private int previousPage() {
int page = currentWizardPage - 1;
while (page > 0) {
while (page >= 0) {
if (screens.get(page).visibility == null || screens.get(page).visibility.isValid())
return page;
page--;
}
return currentWizardPage;
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (permissions.length != 0) {
if (ActivityCompat.checkSelfPermission(this, permissions[0]) == PackageManager.PERMISSION_GRANTED) {
switch (requestCode) {
case AndroidPermission.CASE_STORAGE:
//show dialog after permission is granted
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setMessage(R.string.alert_dialog_storage_permission_text);
alert.setPositiveButton(R.string.ok, null);
alert.show();
break;
case AndroidPermission.CASE_LOCATION:
case AndroidPermission.CASE_SMS:
case AndroidPermission.CASE_BATTERY:
break;
}
}
}
updateButtons();
}
}

View file

@ -0,0 +1,94 @@
package info.nightscout.utils;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Overview.notifications.NotificationWithAction;
public class AndroidPermission {
public static final int CASE_STORAGE = 0x1;
public static final int CASE_SMS = 0x2;
public static final int CASE_LOCATION = 0x3;
public static final int CASE_BATTERY = 0x4;
public static void askForPermission(Activity activity, String[] permission, Integer requestCode) {
boolean test = false;
for (int i = 0; i < permission.length; i++) {
test = test || (ContextCompat.checkSelfPermission(activity, permission[i]) != PackageManager.PERMISSION_GRANTED);
}
if (test) {
ActivityCompat.requestPermissions(activity, permission, requestCode);
}
}
public static void askForPermission(Activity activity, String permission, Integer requestCode) {
String[] permissions = {permission};
if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(activity, permissions, requestCode);
}
public static boolean checkForPermission(Context context, String permission) {
return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
}
public static synchronized void notifyForSMSPermissions(Activity activity) {
if (SP.getBoolean(R.string.smscommunicator_remotecommandsallowed, false)) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
if (!checkForPermission(activity, Manifest.permission.RECEIVE_SMS)) {
NotificationWithAction notification = new NotificationWithAction(Notification.PERMISSION_SMS, MainApp.gs(R.string.smscommunicator_missingsmspermission), Notification.URGENT);
notification.action(MainApp.gs(R.string.request), () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.RECEIVE_SMS,
Manifest.permission.SEND_SMS,
Manifest.permission.RECEIVE_MMS}, AndroidPermission.CASE_SMS));
MainApp.bus().post(new EventNewNotification(notification));
} else
MainApp.bus().post(new EventDismissNotification(Notification.PERMISSION_SMS));
}
}
}
public static synchronized void notifyForBatteryOptimizationPermission(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!checkForPermission(activity, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)) {
NotificationWithAction notification = new NotificationWithAction(Notification.PERMISSION_BATTERY, String.format(MainApp.gs(R.string.needwhitelisting), MainApp.gs(R.string.app_name)), Notification.URGENT);
notification.action(MainApp.gs(R.string.request), () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}, AndroidPermission.CASE_BATTERY));
MainApp.bus().post(new EventNewNotification(notification));
} else
MainApp.bus().post(new EventDismissNotification(Notification.PERMISSION_BATTERY));
}
}
public static synchronized void notifyForStoragePermission(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!checkForPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
NotificationWithAction notification = new NotificationWithAction(Notification.PERMISSION_STORAGE, MainApp.gs(R.string.needstoragepermission), Notification.URGENT);
notification.action(MainApp.gs(R.string.request), () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE}, AndroidPermission.CASE_STORAGE));
MainApp.bus().post(new EventNewNotification(notification));
} else
MainApp.bus().post(new EventDismissNotification(Notification.PERMISSION_STORAGE));
}
}
public static synchronized void notifyForLocationPermissions(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!checkForPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION)) {
NotificationWithAction notification = new NotificationWithAction(Notification.PERMISSION_LOCATION, MainApp.gs(R.string.needlocationpermission), Notification.URGENT);
notification.action(MainApp.gs(R.string.request), () -> AndroidPermission.askForPermission(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, AndroidPermission.CASE_LOCATION));
MainApp.bus().post(new EventNewNotification(notification));
} else
MainApp.bus().post(new EventDismissNotification(Notification.PERMISSION_LOCATION));
}
}
}

View file

@ -289,19 +289,7 @@ public class NSUpload {
public static void uploadProfileSwitch(ProfileSwitch profileSwitch) {
try {
JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.PROFILESWITCH);
data.put("duration", profileSwitch.durationInMinutes);
data.put("profile", profileSwitch.getCustomizedName());
data.put("profileJson", profileSwitch.profileJson);
data.put("profilePlugin", profileSwitch.profilePlugin);
if (profileSwitch.isCPP) {
data.put("CircadianPercentageProfile", true);
data.put("timeshift", profileSwitch.timeshift);
data.put("percentage", profileSwitch.percentage);
}
data.put("created_at", DateUtil.toISOString(profileSwitch.date));
data.put("enteredBy", MainApp.gs(R.string.app_name));
JSONObject data = getJson(profileSwitch);
uploadCareportalEntryToNS(data);
} catch (JSONException e) {
log.error("Unhandled exception", e);
@ -334,19 +322,7 @@ public class NSUpload {
public static void updateProfileSwitch(ProfileSwitch profileSwitch) {
try {
JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.PROFILESWITCH);
data.put("duration", profileSwitch.durationInMinutes);
data.put("profile", profileSwitch.getCustomizedName());
data.put("profileJson", profileSwitch.profileJson);
data.put("profilePlugin", profileSwitch.profilePlugin);
if (profileSwitch.isCPP) {
data.put("CircadianPercentageProfile", true);
data.put("timeshift", profileSwitch.timeshift);
data.put("percentage", profileSwitch.percentage);
}
data.put("created_at", DateUtil.toISOString(profileSwitch.date));
data.put("enteredBy", MainApp.gs(R.string.app_name));
JSONObject data = getJson(profileSwitch);
if (profileSwitch._id != null) {
Context context = MainApp.instance().getApplicationContext();
Bundle bundle = new Bundle();
@ -365,6 +341,24 @@ public class NSUpload {
}
}
private static JSONObject getJson(ProfileSwitch profileSwitch) throws JSONException {
JSONObject data = new JSONObject();
data.put("eventType", CareportalEvent.PROFILESWITCH);
data.put("duration", profileSwitch.durationInMinutes);
data.put("profile", profileSwitch.getCustomizedName());
data.put("profileJson", profileSwitch.profileJson);
data.put("profilePlugin", profileSwitch.profilePlugin);
if (profileSwitch.isCPP) {
data.put("CircadianPercentageProfile", true);
data.put("timeshift", profileSwitch.timeshift);
data.put("percentage", profileSwitch.percentage);
}
data.put("created_at", DateUtil.toISOString(profileSwitch.date));
data.put("enteredBy", MainApp.gs(R.string.app_name));
return data;
}
public static void uploadCareportalEntryToNS(JSONObject data) {
try {
if (data.has("preBolus") && data.has("carbs")) {

View file

@ -7,15 +7,33 @@
android:orientation="vertical"
tools:context=".setupwizard.SetupWizardActivity">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:onClick="exitPressed"
app:srcCompat="@drawable/ic_exit_to_app" />
<TextView
android:id="@+id/sw_exit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:text="@string/exit"
android:textAppearance="@android:style/TextAppearance.Material.Medium"
android:textStyle="bold" />
</LinearLayout>
<TextView
android:id="@+id/sw_content"
android:layout_width="match_parent"
@ -27,6 +45,7 @@
tools:text="Title" />
<ScrollView
android:id="@+id/sw_scrollview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
@ -34,7 +53,6 @@
android:id="@+id/sw_content_fields"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical|center_horizontal"
android:orientation="vertical"
android:padding="16dp" />

View file

@ -170,7 +170,7 @@
<string name="save">Opslaan</string>
<string name="safety">Veiligheid</string>
<string name="send_calibration" formatted="false">Verzend calibratie %.1f naar xDrip?</string>
<string name="sensitivity_warning">Vergeet niet alle gegeten koolhydraten in te geven bij het activeren van de Autosens functie. Anders zullen BG wijzigingen door maaltijden foutief geïnterpreteerd worden!!</string>
<string name="sensitivity_warning">Vergeet niet alle opgenomen koolhydraten in te geven. Anders zullen BG wijzigingen door maaltijden foutief geïnterpreteerd worden!!</string>
<string name="sensitivityaaps">Gevoeligheid AAPS</string>
<string name="sensitivityoref0">Gevoeligheid Oref0</string>
<string name="setbasalquestion">Accepteer nieuw tijdelijk basaal:</string>
@ -410,7 +410,7 @@
<string name="openapsama_autosens_adjusttargets_summary">Standaardwaarde: waar Dit wordt gebruikt om autosens de bevoegdheid te geven BG doelen aan te passen alsook ISF en basalen</string>
<string name="openapsama_autosens_period">Interval voor autosens [u]</string>
<string name="openapsama_autosens_period_summary">Aantal uren in het verleden voor gevoeligheids detectie (koolhy. absorbtie tijd niet meegerekend)</string>
<string name="openapsama_useautosens">Gebruik de AMA autosens functie</string>
<string name="openapsama_useautosens">Activeer AMA autosens</string>
<string name="openapsma">OpenAPS MA</string>
<string name="openapsma_autosensdata_label">Autosens gegevens</string>
<string name="openapsma_disabled">Plugin is gedeactiveerd</string>
@ -544,7 +544,7 @@
<string name="quickwizard">Vaste maaltijd</string>
<string name="quickwizardsettings">Vaste maaltijd instellingen</string>
<string name="removerecord">Verwijder gegeven:</string>
<string name="resend_all_data">Verzend alle gegevens opnieuw</string>
<string name="resend_all_data">Update Wear gegevens</string>
<string name="reset_db_confirm">Wil je echt de databank wissen?</string>
<string name="sensitivity_shortname">SENS</string>
<string name="short_avgdelta">Klein gemiddeld verschil</string>
@ -739,5 +739,211 @@
<string name="ns_create_announcements_from_errors_summary">Creëer een Nightscout melding voor storingen en lokale waarschuwingen (ook zichtbaar inder het Careportal en behandelingen)</string>
<string name="combo_suspious_bolus_time">Datum/tijd van de geleverde bolus op de pomp is niet correct, IOB is waarschijnlijk foutief. Controleer aub de datum/tijd op de pomp.</string>
<string name="profileswitch_ismissing">Profiel wissel ontbreekt. Doe aub een profiel wissel of duw op Activeer Profiel in het Lokale profiel.</string>
<string name="loop_tbrsetbypump_label">tijdelijk basaal gezet door pomp</string>
<string name="resistantadult">insuline resistente volwassene</string>
<string name="smb_shortname">SMB</string>
<string name="enableuam">Activeer UAM</string>
<string name="enablesmb">Activeer SMB</string>
<string name="changed">Verwisseld</string>
<string name="pump_stopped_uppercase">Pomp Gestopt</string>
<string name="status_updated">Status vernieuwd</string>
<string name="status_no_colon">status</string>
<string name="insightpump">Insight pomp</string>
<string name="fr_lang">Français</string>
<string name="hypo">Hypo</string>
<string name="openapssmb">OpenAPS SMB</string>
<string name="enablesmb_summary">SMB in plaats van tijdelijke basalen voor snellere reactie</string>
<string name="enableuam_summary">Detectie van niet aangekondigde maaltijden</string>
<string name="shortminute">m</string>
<string name="shorthour">u</string>
<string name="insightpump_shortname">Insight</string>
<string name="hypo_duration">Hypo tijdsduur</string>
<string name="combo_pump_state_initializing">Initialiseren</string>
<string name="log_book">Logboek</string>
<string name="alert_e13">Storing E13: Taal storing</string>
<string name="alert_e10">Storing E10: Terugdraai storing</string>
<string name="alert_e7">Storing E7: Elektronische storing</string>
<string name="alert_e6">Storing E6: Mechanische storing</string>
<string name="insight_stay_always_connected">Blijf altijd verbonden</string>
<string name="insight_history_syncing">Syncroniseren</string>
<string name="insight_history_idle">Rust</string>
<string name="insight_history_busy">Bezig</string>
<string name="insight_history_synced">Gesyncroniseerd</string>
<string name="insight_not_authorized">Niet geautoriseerd</string>
<string name="insight_incompatible">incompatibel</string>
<string name="second">seconde</string>
<string name="minute">minuut</string>
<string name="hour">uur</string>
<string name="day">dag</string>
<string name="week">week</string>
<string name="time_plural">s</string>
<string name="statistics">Statistieken</string>
<string name="automatically_connect_when">Automatische verbinden wanneer AndroidAPS scherm geopend wordt, voordat er een pomp commande wordt uitgevoerd om zo de verbindingsvertraging te omzeilen</string>
<string name="insight_code_rejected">Code geweigerd</string>
<string name="not_recommended_due_to_battery_drain">Niet aangewezen door hoog batterij verbuik</string>
<string name="enablesmbalways">Activeer SMB altijd</string>
<string name="enablesmbalways_summary">SMB altijd onafhangkelijk van bolussen. Enkel mogelijk met een BG bron met goed gefilterde data zoals de G5</string>
<string name="enablesmbaftercarbs">Activeer SMB na koolhydraten</string>
<string name="enablesmbaftercarbs_summary">SMB actief gedurende 6u, zelfs met 0 COB. Enkel mogelijk met een BG bron met goed gefilterde data zoals de G5</string>
<string name="overview_insulin_label">Insuline</string>
<string name="overview_carbs_label">Koolhydraten</string>
<string name="overview_buttons_selection">Knoppen</string>
<string name="show_calibration_button_summary">Stuurt een kalibratie naar xDrip+ of opent het G5 calibratie venster</string>
<string name="show_cgm_button_summary">Opent xDrip+, terug knop voor terug naar AAPS te gaan</string>
<string name="carb_increment_button_message">Aantal koolhydraten toevoegen wanneer de knop wordt ingeduwd</string>
<string name="insulin_increment_button_message">Hoeveelheid insuline dat wordt toegevoegd wanneer er op de knop geduwt word</string>
<string name="error_starting_cgm">Kon de CGM applicatie niet starten. Zorg dat deze geïnstalleerd is.</string>
<string name="overview_cgm">CGM</string>
<string name="nav_historybrowser">Historiek venster</string>
<string name="wear_notifysmb_title">Waarschuw bij SMB</string>
<string name="let_temp_basal_run">Laat tijdelijk basaal lopen</string>
<string name="wear_predictions_title">Voorspellingen</string>
<string name="fabric_upload">Fabric Upload</string>
<string name="category">Categorie</string>
<string name="subcategory">subcategorie</string>
<string name="bolusrecordedonly">Bolus zal enkel opgeslaan worden</string>
<string name="loop_smbsetbypump_label">SMB op de pomp ingesteld</string>
<string name="overview_show_sensitivity">Gevoeligheid</string>
<string name="overview_show_deviations">Afwijkingen</string>
<string name="don_t_bolus_record_only">Geef geen bolus, enkel opslaan in database</string>
<string name="overview_show_basals">Basalen</string>
<string name="value_unavailable_short">n/a</string>
<string name="wear_wizard_settings">Wizard instellingen</string>
<string name="wear_wizard_settings_summary">Berekeningen inclusief in het resultaat van de wizard</string>
<string name="wear_display_settings">Scherm instellingen</string>
<string name="wear_general_settings">Algemene instellingen</string>
<string name="alert_w31">Waarschuwing W31: Patroon bijna leeg</string>
<string name="alert_w38">Waarschuwing W38: Bolus geannuleerd</string>
<string name="alert_w36">Waarschuwing W36: Tijdelijk basaal geannuleerd</string>
<string name="alert_w32">Waarschuwing W32: Batterij niveau laag</string>
<string name="alert_w33">Waarschuwing W33: Datum/tijd onjuist</string>
<string name="alert_w34">Waarschuwing W34: Einde van garantie periode</string>
<string name="alert_m20">Onderhoudsmelding M20: Insuline patroon niet geplaatst</string>
<string name="alert_m21">Onderhoudsmelding M21: Insuline patroon leeg</string>
<string name="alert_m22">Onderhoudsmelding M22: Batterij leeg</string>
<string name="alert_m23">Onderhoudsmelding M23: Automatische uit</string>
<string name="alert_m24">Onderhoudsmelding M24: Verstopping</string>
<string name="alert_m25">Onderhoudsmelding m25: Huur periode voorbij - einde van werking</string>
<string name="alert_m26">Onderhoudsmelding M26: Insuline patroon wissl niet compleet</string>
<string name="alert_m27">Onderhoudsmelding M27: Gegevens download mislukt</string>
<string name="alert_m28">Onderhoudsmelding M26: Gepauzeerde modus verlopen</string>
<string name="alert_m29">Onderhoudsmelding M29: Batterij type niet ingesteld</string>
<string name="alert_m30">Onderhoudsmelding M30: Insuline patroon type niet ingesteld</string>
<string name="alert_w39">Waarschuwing W39: Huurperiode waarschuwing</string>
<string name="ns_wifi_ssids">WiFi SSID</string>
<string name="ns_wifionly">Gebuik enkel de WiFi verbinding</string>
<string name="ns_wifi_allowedssids">Toegelaten SSIDs (gescheiden door puntkomma)</string>
<string name="pump_stopped">Pomp gestopt</string>
<string name="pump_started">Pomp gestart</string>
<string name="pump_paused">Pomp gepauzeerd</string>
<string name="absorption_cutoff_title">Maximum maaltijd absorbtie tijd (h)</string>
<string name="time">Tijd</string>
<string name="overview_show_notes_field_in_dialogs_title">Toon het notities veld in het behandelings dialoog</string>
<string name="cgm">CGM</string>
<string name="food_short">Voeding</string>
<string name="reset">Reset</string>
<string name="waitingfortimesynchronization">Wachttijd voor syncronisatie (%d sec)</string>
<string name="ago">Voorbij</string>
<string name="with">met</string>
<string name="insight_active_tbr">Actieve TBR</string>
<string name="insight_min_left">resterende minuten</string>
<string name="insight_startup_uppercase">Opstarten</string>
<string name="insight_needs">benodigd</string>
<string name="insight_min">min</string>
<string name="insight_last_completed_action">Laatst afgewerkte actie</string>
<string name="insight_total_with">totaal</string>
<string name="enablesmbwithcob">Activeer SMB met Koolhydraten</string>
<string name="enablesmbwithcob_summary">SMB actief tijdens actieve koolhydraten</string>
<string name="enablesmbwithtemptarget">Gebruik SMB met tijdelijke doelen</string>
<string name="enablesmbwithtemptarget_summary">Gebruik SMB bij een actief tijdelijk basaal (binnenkort eten, inspanningen)</string>
<string name="enablesmbwithhightemptarget">Gebruik SMB met een hoog tijdelijk doel</string>
<string name="enablesmbwithhightemptarget_summary">Gebruik SMB tijdens een verhoogd tijdelijk doel (Inspanningen)</string>
<string name="start_activity_tt">Start inspanning TT</string>
<string name="start_eating_soon_tt">Start binnenkort eten TT</string>
<string name="temptargetshort">TT</string>
<string name="combo_bolus_count">Aantal bolussen</string>
<string name="combo_tbr_count">Aantal TBR</string>
<string name="objectivenotstarted">Doel %d niet gestart</string>
<string name="wear_notifysmb_summary">Toon SMB op horloge zoals gewone bolussen.</string>
<string name="wear_predictions_summary">Toon de voorspellingen op het horloge</string>
<string name="data_choices">Data Keuzes</string>
<string name="allow_automated_crash_reporting">Sta automatische crashrapporten en verder gebruik van data toe zodat deze naar de ontwikelaars via fabric.io kan verzonden worden.</string>
<string name="ns_autobackfill_title">Automatische BG aanvullen</string>
<string name="openapsama_current_basal_safety_multiplier">Actuele veiliheids verhoger van basaal</string>
<string name="openapsama_max_daily_safety_multiplier">Maximale dagelijkse veiligheids vermeningvuldigings factor</string>
<string name="openapsama_bolussnooze_dia_divisor">Bolus snooze dia deler</string>
<string name="openapsama_autosens_min">Min autosens factor</string>
<string name="openapsama_autosens_max">Max autosens factor</string>
<string name="ns_allowroaming">Sta verbinding tijdens roaming toe</string>
<string name="connectionsettings_title">Verbindings instellingen</string>
<string name="ns_chargingonly">Enkel tijdens opladen</string>
<string name="boluserrorcode">Gevraagd: %.2fU Afgegeven: %.2fU Storings code: %d</string>
<string name="ro_lang">Românesc</string>
<string name="zh_lang">Chinese</string>
<string name="openapsama_autosens_adjusttargets">Autosens regelt de BG streefwaarde bij</string>
<string name="hypo_target">Hypo streefwaarde</string>
<string name="smbmaxminutes_summary">Maximum aantal minuten basaal om de SMB te limiteren tot</string>
<string name="connect_preemptively">Verbind preëntief</string>
<string name="overview_show_cob">Opgenomen Koolhydraten</string>
<string name="overview_show_iob">Opgenomen Insuline</string>
<string name="no_action_selected">Geen actie geselecteerd, er zal niets uitgevoerd worden</string>
<string name="insight_keep_alive_status">Keep-alive status</string>
<string name="g5appnotdetected">Update dexcom G5 app naar de ondersteunde versie</string>
<string name="ns_autobackfill_summary">automatische ontbenkende BGs aanvullen van NS</string>
<string name="start_hypo_tt">Start Hypo TT</string>
<string name="engineering_mode_enabled">Engineering modus is geactiveerd</string>
<string name="not_eng_mode_or_release">Engineering modus is niet geactiveerd en dit is niet de relaese branche</string>
<string name="objectivenotfinished" formatted="false">Doel %d niet afgewerkt</string>
<string name="pumpisnottempbasalcapable">Pomp kan geen tijdelijk basaal aanvaarden</string>
<string name="novalidbasalrate">Geen plausibel basale snelheid van pomp kunnen lezen</string>
<string name="autosensdisabledinpreferences">Autosens gedeactiveerd in de voorkeuren</string>
<string name="closedmodedisabledinpreferences">Closed Loop modus gedeactiveerd in de voorkeuren</string>
<string name="smbdisabledinpreferences">SMB gedeactiveerd in de voorkeuren</string>
<string name="insight_unknown">Ongekend</string>
<string name="limitingbasalratio">Beperken van basaal tot max %.2f E/U wegens de %s</string>
<string name="pumplimit">Pomp limiet</string>
<string name="itmustbepositivevalue">dit moet een positieve waarde zijn</string>
<string name="basal_set_correctly">Basaal correct ingesteld</string>
<string name="limitingpercentrate" formatted="false">Begrezen van max procentuele wijzigen tot %d%% want de %s</string>
<string name="smbalwaysdisabled">SMB altijd gedeactiveerd doordat de gekozen BG bron geen optimale filtering toepast</string>
<string name="smbnotallowedinopenloopmode">SMB niet toegestaan in Open Loop modus</string>
<string name="loopdisconnectedfor">Niet verbonden (%d m)</string>
<string name="hardlimit">max limiet (SC)</string>
<string name="unsafeusage">Onveilig gebruik</string>
<string name="closed_loop_disabled_on_dev_branch">Dev cersie actief. Closed loop gedeactiveerd</string>
<string name="insight_actually_cancel_tbr_summary">Anneuleren van een TBR zorgt voor een alarm op de pomp, daarom wordt pomp op 90% gezet voor 1 minuut</string>
<string name="insight_waiting_for_code">Wacht op confirmatie van code</string>
<string name="insight_incompatible_compantion_app_we_need_version">Incompatiebele hulp app, we hebben deze versie nodig</string>
<string name="insight_app_binding">app koppeling</string>
<string name="insight_use_real_tbr_cancels">Gebruik echte TBR uischakelingen</string>
<string name="insight_not_connected_to_companion_app">Niet verbonden met de hulpapp!</string>
<string name="insight_companion_app_not_installed">Hulp app lijkt niet geïnstalleerd</string>
<string name="record_pump_site_change">Markeer een infuuwissel in NS</string>
<string name="readstatusfailed">Leezen van status mislukt</string>
<string name="record_insulin_cartridge_change">Markeer een insuline ampull wissel in NS</string>
<string name="automatic_careportal_events">Automatische Careportal gebeurtenissen</string>
<string name="insight_remaining_over">resterende van</string>
<string name="insight_upfront_with">op voorhand met</string>
<string name="insight_keepalive_format_string">%ds verloopt %s</string>
<string name="about_link_urls">" http://www.androidaps.org facebook: http://facebook.androidaps.org"</string>
<string name="firstinsulinincrement">"Eerste insuline increment"</string>
<string name="secondinsulinincrement">Tweede insuline increment</string>
<string name="thirdinsulinincrement">Derde insuline increment</string>
<string name="firstcarbsincrement">Eerste koolhydraten increment</string>
<string name="secondcarbsincrement">Tweede koolhydraten increment</string>
<string name="thirdcarbsincrement">Derde koolhydraten increment</string>
<string name="limitingbolus" formatted="false">Bolus beperkt tot %.1f E doordat %s</string>
<string name="smb_frequency_exceeded">Er is een bolus toegediend gedurende de afgelopen 3 minuten, SMB wordt overgeslagen</string>
<string name="limitingmaxiob" formatted="false">Max IOB wordt beperkt tot %1.f E doordat %s</string>
<string name="limitingcarbs" formatted="false">Koolhydraten worden beperkt tot %d gr doordat %s</string>
<string name="maxvalueinpreferences">Maximum waarde in voorkeuren</string>
<string name="limitingiob" formatted="false">IOB gelimmiteerd tot %.1f E doordat %s</string>
<string name="automatically_upload_insulin_cannula_and_battery_changes_to_nightscout">Automatische Insuline, infusieset wissels, batterij wissels en pomp alarmen naar NS uploaden</string>
<string name="absorption_cutoff_summary">Tijdspanne waarbinnen elke maaltijd vollezig is opgenomen. Resterende KH worden niet mee gerekend.</string>
<string name="openapssmb_maxiob_title">Max totaal IOB dat OpenAPS niet kan overschrijden (E)</string>
<string name="maxbasalmultiplier">Max basaal vermenigvuldiger</string>
<string name="maxdailybasalmultiplier">Max dagelijks basaal vermenigvuldiger</string>
<string name="openapssmb_maxiob_summary">MAX IOB in OpenAPS context, OpenAPS zal geen extra insuline toedenen als de actuele IOB onderstaande waarde overschreden heeft</string>
<string name="do_not_bolus_record_only">"Geen bolus toedienen enkel in behandeleingen zetten"</string>
</resources>