89d59584d5
* origin/dev: prepend line feed like suggested on jamoto code review Rename method to reflect jomoto code review Unit tests are always in engmode Fix boolean stuff in accordance to code review with adrian Cleanup boolean algrabra, add method for environment retrieval from logcontexxt Determine directory from logback more checks for null profile Disallow profile store on pump if on dev branch but not in engineering mode Disable profile switch if not in Engineering mode and on dev branch Add info to About dialog when engineering mode is enabled. On start, show notification if on dev-branch, but not EM, so CL is disabled. Add basic Engineering mode. # Conflicts: # app/src/main/java/info/nightscout/androidaps/MainActivity.java # app/src/main/java/info/nightscout/androidaps/plugins/Overview/notifications/Notification.java # app/src/main/java/info/nightscout/androidaps/queue/CommandQueue.java # app/src/main/res/values/strings.xml
436 lines
19 KiB
Java
436 lines
19 KiB
Java
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;
|
|
import android.support.v7.widget.PopupMenu;
|
|
import android.text.SpannableString;
|
|
import android.text.method.LinkMovementMethod;
|
|
import android.text.util.Linkify;
|
|
import android.view.MenuInflater;
|
|
import android.view.MenuItem;
|
|
import android.view.MotionEvent;
|
|
import android.view.View;
|
|
import android.view.WindowManager;
|
|
import android.view.inputmethod.InputMethodManager;
|
|
import android.widget.EditText;
|
|
import android.widget.ImageButton;
|
|
import android.widget.TextView;
|
|
|
|
import com.joanzapata.iconify.Iconify;
|
|
import com.joanzapata.iconify.fonts.FontAwesomeModule;
|
|
import com.squareup.otto.Subscribe;
|
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import info.nightscout.androidaps.data.Profile;
|
|
import info.nightscout.androidaps.events.EventAppExit;
|
|
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.plugins.ConfigBuilder.ConfigBuilderPlugin;
|
|
import info.nightscout.androidaps.plugins.Food.FoodPlugin;
|
|
import info.nightscout.androidaps.plugins.Overview.events.EventSetWakeLock;
|
|
import info.nightscout.androidaps.tabs.SlidingTabLayout;
|
|
import info.nightscout.androidaps.tabs.TabPageAdapter;
|
|
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;
|
|
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
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();
|
|
doMigrations();
|
|
if (Config.logFunctionCalls)
|
|
log.debug("onCreate");
|
|
|
|
onStatusEvent(new EventSetWakeLock(SP.getBoolean("lockscreen", false)));
|
|
|
|
registerBus();
|
|
setUpTabs(false);
|
|
}
|
|
|
|
@Subscribe
|
|
public void onStatusEvent(final EventSetWakeLock ev) {
|
|
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
|
if (ev.lock) {
|
|
mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "AAPS");
|
|
if (!mWakeLock.isHeld())
|
|
mWakeLock.acquire();
|
|
} else {
|
|
if (mWakeLock != null && mWakeLock.isHeld())
|
|
mWakeLock.release();
|
|
}
|
|
}
|
|
|
|
@Subscribe
|
|
public void onStatusEvent(final EventRefreshGui ev) {
|
|
String lang = SP.getString("language", "en");
|
|
LocaleHelper.setLocale(getApplicationContext(), lang);
|
|
runOnUiThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (ev.recreate) {
|
|
recreate();
|
|
} else {
|
|
try { // activity may be destroyed
|
|
setUpTabs(true);
|
|
} catch (IllegalStateException e) {
|
|
log.error("Unhandled exception", e);
|
|
}
|
|
}
|
|
|
|
boolean lockScreen = BuildConfig.NSCLIENTOLNY && SP.getBoolean("lockscreen", false);
|
|
if (lockScreen)
|
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
else
|
|
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
}
|
|
});
|
|
}
|
|
|
|
private void setUpTabs(boolean switchToLast) {
|
|
TabPageAdapter pageAdapter = new TabPageAdapter(getSupportFragmentManager(), this);
|
|
for (PluginBase p : MainApp.getPluginsList()) {
|
|
pageAdapter.registerNewFragment(p);
|
|
}
|
|
ViewPager mPager = (ViewPager) findViewById(R.id.pager);
|
|
mPager.setAdapter(pageAdapter);
|
|
SlidingTabLayout mTabs = (SlidingTabLayout) findViewById(R.id.tabs);
|
|
mTabs.setViewPager(mPager);
|
|
if (switchToLast)
|
|
mPager.setCurrentItem(pageAdapter.getCount() - 1, false);
|
|
}
|
|
|
|
private void registerBus() {
|
|
try {
|
|
MainApp.bus().unregister(this);
|
|
} catch (RuntimeException x) {
|
|
// Ignore
|
|
}
|
|
MainApp.bus().register(this);
|
|
}
|
|
|
|
private void checkEula() {
|
|
//SP.removeBoolean(R.string.key_i_understand);
|
|
boolean IUnderstand = SP.getBoolean(R.string.key_i_understand, false);
|
|
if (!IUnderstand) {
|
|
Intent intent = new Intent(getApplicationContext(), AgreementActivity.class);
|
|
startActivity(intent);
|
|
finish();
|
|
}
|
|
}
|
|
|
|
private void doMigrations() {
|
|
|
|
checkUpgradeToProfileTarget();
|
|
|
|
// guarantee that the unreachable threshold is at least 30 and of type String
|
|
// Added in 1.57 at 21.01.2018
|
|
Integer unreachable_threshold = SP.getInt(R.string.key_pump_unreachable_threshold, 30);
|
|
SP.remove(R.string.key_pump_unreachable_threshold);
|
|
if (unreachable_threshold < 30) unreachable_threshold = 30;
|
|
SP.putString(R.string.key_pump_unreachable_threshold, unreachable_threshold.toString());
|
|
}
|
|
|
|
|
|
private void checkUpgradeToProfileTarget() { // TODO: can be removed in the future
|
|
boolean oldKeyExists = SP.contains("openapsma_min_bg");
|
|
if (oldKeyExists) {
|
|
Profile profile = MainApp.getConfigBuilder().getProfile();
|
|
String oldRange = SP.getDouble("openapsma_min_bg", 0d) + " - " + SP.getDouble("openapsma_max_bg", 0d);
|
|
String newRange = "";
|
|
if (profile != null) {
|
|
newRange = profile.getTargetLow() + " - " + profile.getTargetHigh();
|
|
}
|
|
String message = "Target range is changed in current version.\n\nIt's not taken from preferences but from profile.\n\n!!! REVIEW YOUR SETTINGS !!!";
|
|
message += "\n\nOld settings: " + oldRange;
|
|
message += "\nProfile settings: " + newRange;
|
|
OKDialog.show(this, "Target range change", message, new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
SP.remove("openapsma_min_bg");
|
|
SP.remove("openapsma_max_bg");
|
|
SP.remove("openapsma_target_bg");
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
//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, getString(R.string.pleaseallowpermission), String.format(getString(R.string.needwhitelisting), getString(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 = getString(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:
|
|
//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:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean dispatchTouchEvent(MotionEvent event) {
|
|
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
|
View v = getCurrentFocus();
|
|
if (v instanceof EditText) {
|
|
Rect outRect = new Rect();
|
|
v.getGlobalVisibleRect(outRect);
|
|
if (!outRect.contains((int) event.getRawX(), (int) event.getRawY())) {
|
|
v.clearFocus();
|
|
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
|
|
}
|
|
}
|
|
}
|
|
return super.dispatchTouchEvent(event);
|
|
}
|
|
|
|
@Override
|
|
public void onClick(final View v) {
|
|
final Activity activity = this;
|
|
switch (v.getId()) {
|
|
case R.id.overview_menuButton:
|
|
PopupMenu popup = new PopupMenu(v.getContext(), v);
|
|
MenuInflater inflater = popup.getMenuInflater();
|
|
inflater.inflate(R.menu.menu_main, popup.getMenu());
|
|
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
|
@Override
|
|
public boolean onMenuItemClick(MenuItem item) {
|
|
int id = item.getItemId();
|
|
switch (id) {
|
|
case R.id.nav_preferences:
|
|
PasswordProtection.QueryPassword(v.getContext(), R.string.settings_password, "settings_password", new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
Intent i = new Intent(v.getContext(), PreferencesActivity.class);
|
|
i.putExtra("id", -1);
|
|
startActivity(i);
|
|
}
|
|
}, null);
|
|
break;
|
|
case R.id.nav_historybrowser:
|
|
startActivity(new Intent(v.getContext(), HistoryBrowseActivity.class));
|
|
break;
|
|
case R.id.nav_resetdb:
|
|
new AlertDialog.Builder(v.getContext())
|
|
.setTitle(R.string.nav_resetdb)
|
|
.setMessage(R.string.reset_db_confirm)
|
|
.setNegativeButton(android.R.string.cancel, null)
|
|
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
|
@Override
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
MainApp.getDbHelper().resetDatabases();
|
|
// should be handled by Plugin-Interface and
|
|
// additional service interface and plugin registry
|
|
MainApp.getSpecificPlugin(FoodPlugin.class).getService().resetFood();
|
|
}
|
|
})
|
|
.create()
|
|
.show();
|
|
break;
|
|
case R.id.nav_export:
|
|
ImportExportPrefs.verifyStoragePermissions(activity);
|
|
ImportExportPrefs.exportSharedPreferences(activity);
|
|
break;
|
|
case R.id.nav_import:
|
|
ImportExportPrefs.verifyStoragePermissions(activity);
|
|
ImportExportPrefs.importSharedPreferences(activity);
|
|
break;
|
|
case R.id.nav_show_logcat:
|
|
LogDialog.showLogcat(v.getContext());
|
|
break;
|
|
case R.id.nav_about:
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
|
|
builder.setTitle(getString(R.string.app_name) + " " + BuildConfig.VERSION);
|
|
if (Config.NSCLIENT || Config.G5UPLOADER)
|
|
builder.setIcon(R.mipmap.yellowowl);
|
|
else
|
|
builder.setIcon(R.mipmap.blueowl);
|
|
String message = "Build: " + BuildConfig.BUILDVERSION + "\n";
|
|
message += MainApp.sResources.getString(R.string.configbuilder_nightscoutversion_label) + " " + ConfigBuilderPlugin.nightscoutVersionName;
|
|
if (MainApp.engineeringMode)
|
|
message += "\n" + MainApp.gs(R.string.engineering_mode_enabled);
|
|
message += getString(R.string.about_link_urls);
|
|
final SpannableString messageSpanned = new SpannableString(message);
|
|
Linkify.addLinks(messageSpanned, Linkify.WEB_URLS);
|
|
builder.setMessage(messageSpanned);
|
|
builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), null);
|
|
AlertDialog alertDialog = builder.create();
|
|
alertDialog.show();
|
|
((TextView)alertDialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
|
|
break;
|
|
case R.id.nav_exit:
|
|
log.debug("Exiting");
|
|
MainApp.instance().stopKeepAliveService();
|
|
MainApp.bus().post(new EventAppExit());
|
|
MainApp.closeDbHelper();
|
|
finish();
|
|
System.runFinalization();
|
|
System.exit(0);
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
popup.show();
|
|
break;
|
|
}
|
|
}
|
|
}
|