Merge remote-tracking branch 'origin/dev' into dev-merge

* 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
This commit is contained in:
Johannes Mockenhaupt 2018-03-18 19:47:23 +01:00
commit 89d59584d5
No known key found for this signature in database
GPG key ID: 9E1EA6AF7BBBB0D1
20 changed files with 97 additions and 24 deletions

View file

@ -1,6 +1,6 @@
<configuration> <configuration>
<!-- Create a file appender for a log in the application's data directory --> <!-- Create a file appender for a log in the application's data directory -->
<property name="EXT_FILES_DIR" value="${EXT_DIR:-/sdcard}/Android/data/${PACKAGE_NAME}/files"/> <property scope="context" name="EXT_FILES_DIR" value="${EXT_DIR:-/sdcard}/Android/data/${PACKAGE_NAME}/files"/>
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"> <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${EXT_FILES_DIR}/AndroidAPS.log</file> <file>${EXT_FILES_DIR}/AndroidAPS.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

View file

@ -13,6 +13,7 @@ import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.SeekBar; import android.widget.SeekBar;
import android.widget.TextView;
import com.jjoe64.graphview.GraphView; import com.jjoe64.graphview.GraphView;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
@ -58,6 +59,8 @@ public class HistoryBrowseActivity extends AppCompatActivity {
GraphView iobGraph; GraphView iobGraph;
@BindView(R.id.historybrowse_seekBar) @BindView(R.id.historybrowse_seekBar)
SeekBar seekBar; SeekBar seekBar;
@BindView(R.id.historybrowse_noprofile)
TextView noProfile;
private int rangeToDisplay = 24; // for graph private int rangeToDisplay = 24; // for graph
private long start; private long start;
@ -182,6 +185,14 @@ public class HistoryBrowseActivity extends AppCompatActivity {
void updateGUI(String from) { void updateGUI(String from) {
final PumpInterface pump = ConfigBuilderPlugin.getActivePump(); final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
final Profile profile = MainApp.getConfigBuilder().getProfile(); final Profile profile = MainApp.getConfigBuilder().getProfile();
if (profile == null) {
noProfile.setVisibility(View.VISIBLE);
return;
} else {
noProfile.setVisibility(View.GONE);
}
final String units = profile.getUnits(); final String units = profile.getUnits();
double lowLineSetting = SP.getDouble("low_mark", Profile.fromMgdlToUnits(OverviewPlugin.bgTargetLow, units)); double lowLineSetting = SP.getDouble("low_mark", Profile.fromMgdlToUnits(OverviewPlugin.bgTargetLow, units));

View file

@ -404,6 +404,8 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
builder.setIcon(R.mipmap.blueowl); builder.setIcon(R.mipmap.blueowl);
String message = "Build: " + BuildConfig.BUILDVERSION + "\n"; String message = "Build: " + BuildConfig.BUILDVERSION + "\n";
message += MainApp.sResources.getString(R.string.configbuilder_nightscoutversion_label) + " " + ConfigBuilderPlugin.nightscoutVersionName; 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); message += getString(R.string.about_link_urls);
final SpannableString messageSpanned = new SpannableString(message); final SpannableString messageSpanned = new SpannableString(message);
Linkify.addLinks(messageSpanned, Linkify.WEB_URLS); Linkify.addLinks(messageSpanned, Linkify.WEB_URLS);

View file

@ -20,8 +20,10 @@ import net.danlew.android.joda.JodaTimeAndroid;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import ch.qos.logback.classic.LoggerContext;
import info.nightscout.androidaps.Services.Intents; import info.nightscout.androidaps.Services.Intents;
import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.DatabaseHelper;
import info.nightscout.androidaps.interfaces.InsulinInterface; import info.nightscout.androidaps.interfaces.InsulinInterface;
@ -46,6 +48,8 @@ import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin; import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin; import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin; import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Persistentnotification.PersistentNotificationPlugin; import info.nightscout.androidaps.plugins.Persistentnotification.PersistentNotificationPlugin;
import info.nightscout.androidaps.plugins.ProfileLocal.LocalProfilePlugin; import info.nightscout.androidaps.plugins.ProfileLocal.LocalProfilePlugin;
import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin; import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
@ -97,6 +101,9 @@ public class MainApp extends Application {
private static AckAlarmReceiver ackAlarmReciever = new AckAlarmReceiver(); private static AckAlarmReceiver ackAlarmReciever = new AckAlarmReceiver();
private LocalBroadcastManager lbm; private LocalBroadcastManager lbm;
public static boolean devBranch;
public static boolean engineeringMode;
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
@ -142,7 +149,7 @@ public class MainApp extends Application {
if (Config.HWPUMPS) pluginsList.add(DanaRSPlugin.getPlugin()); if (Config.HWPUMPS) pluginsList.add(DanaRSPlugin.getPlugin());
if (Config.HWPUMPS) pluginsList.add(ComboPlugin.getPlugin()); if (Config.HWPUMPS) pluginsList.add(ComboPlugin.getPlugin());
pluginsList.add(CareportalPlugin.getPlugin()); pluginsList.add(CareportalPlugin.getPlugin());
// if (Config.DANAR) pluginsList.add(InsightPumpPlugin.getPlugin()); // <-- Enable Insight plugin here if (Config.DANAR && engineeringMode) pluginsList.add(InsightPumpPlugin.getPlugin()); // <-- Enable Insight plugin here
if (Config.MDI) pluginsList.add(MDIPlugin.getPlugin()); if (Config.MDI) pluginsList.add(MDIPlugin.getPlugin());
if (Config.VIRTUALPUMP) pluginsList.add(VirtualPumpPlugin.getPlugin()); if (Config.VIRTUALPUMP) pluginsList.add(VirtualPumpPlugin.getPlugin());
if (Config.APS) pluginsList.add(LoopPlugin.getPlugin()); if (Config.APS) pluginsList.add(LoopPlugin.getPlugin());
@ -198,6 +205,16 @@ public class MainApp extends Application {
} }
}).start(); }).start();
String extFilesDir = this.getLogDirectory();
File engineeringModeSemaphore = new File(extFilesDir,"engineering_mode");
engineeringMode = engineeringModeSemaphore.exists() && engineeringModeSemaphore.isFile();
devBranch = BuildConfig.VERSION.contains("dev");
if (!isEngineeringModeOrRelease()) {
Notification n = new Notification(Notification.TOAST_ALARM, gs(R.string.closed_loop_disabled_on_dev_branch), Notification.NORMAL);
bus().post(new EventNewNotification(n));
}
} }
private void registerLocalBroadcastReceiver() { private void registerLocalBroadcastReceiver() {
@ -364,6 +381,15 @@ public class MainApp extends Application {
return null; return null;
} }
public static boolean isEngineeringModeOrRelease() {
return engineeringMode || !devBranch;
}
private String getLogDirectory() {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
return lc.getProperty("EXT_FILES_DIR");
}
@Override @Override
public void onTerminate() { public void onTerminate() {
super.onTerminate(); super.onTerminate();

View file

@ -127,12 +127,14 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL
return; return;
} }
final PumpInterface pump = ConfigBuilderPlugin.getActivePump(); final PumpInterface pump = ConfigBuilderPlugin.getActivePump();
if (!pump.getPumpDescription().isSetBasalProfileCapable || !pump.isInitialized() || pump.isSuspended()) final boolean basalprofileEnabled = MainApp.isEngineeringModeOrRelease()
&& pump.getPumpDescription().isSetBasalProfileCapable;
if (!basalprofileEnabled || !pump.isInitialized() || pump.isSuspended())
profileSwitch.setVisibility(View.GONE); profileSwitch.setVisibility(View.GONE);
else else
profileSwitch.setVisibility(View.VISIBLE); profileSwitch.setVisibility(View.VISIBLE);
if (!pump.getPumpDescription().isExtendedBolusCapable || !pump.isInitialized() || pump.isSuspended() || pump.isFakingTempsByExtendedBoluses()) { if (!pump.getPumpDescription().isExtendedBolusCapable || !pump.isInitialized() || pump.isSuspended() || pump.isFakingTempsByExtendedBoluses()) {
extendedBolus.setVisibility(View.GONE); extendedBolus.setVisibility(View.GONE);
extendedBolusCancel.setVisibility(View.GONE); extendedBolusCancel.setVisibility(View.GONE);

View file

@ -181,7 +181,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick
profileSpinner.setSelection(p); profileSpinner.setSelection(p);
} }
final Double bg = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData() != null ? GlucoseStatus.getGlucoseStatusData().glucose : 0d, profile != null ? profile.getUnits() : Constants.MGDL); final Double bg = Profile.fromMgdlToUnits(GlucoseStatus.getGlucoseStatusData() != null ? GlucoseStatus.getGlucoseStatusData().glucose : 0d, units);
// temp target // temp target
final ArrayList<CharSequence> reasonList = new ArrayList<CharSequence>(); final ArrayList<CharSequence> reasonList = new ArrayList<CharSequence>();

View file

@ -102,6 +102,7 @@ public class SafetyPlugin implements PluginBase, ConstraintsInterface {
**/ **/
@Override @Override
public boolean isClosedModeEnabled() { public boolean isClosedModeEnabled() {
if (!MainApp.isEngineeringModeOrRelease()) return false;
String mode = SP.getString("aps_mode", "open"); String mode = SP.getString("aps_mode", "open");
return mode.equals("closed") && BuildConfig.CLOSEDLOOP; return mode.equals("closed") && BuildConfig.CLOSEDLOOP;
} }

View file

@ -444,15 +444,15 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com
} }
private void calculateInsulin() { private void calculateInsulin() {
ProfileStore profile = ConfigBuilderPlugin.getActiveProfileInterface().getProfile(); ProfileStore profileStore = ConfigBuilderPlugin.getActiveProfileInterface().getProfile();
if (profileSpinner == null || profileSpinner.getSelectedItem() == null) if (profileSpinner == null || profileSpinner.getSelectedItem() == null || profileStore == null)
return; // not initialized yet return; // not initialized yet
String selectedAlternativeProfile = profileSpinner.getSelectedItem().toString(); String selectedAlternativeProfile = profileSpinner.getSelectedItem().toString();
Profile specificProfile; Profile specificProfile;
if (selectedAlternativeProfile.equals(MainApp.sResources.getString(R.string.active))) if (selectedAlternativeProfile.equals(MainApp.sResources.getString(R.string.active)))
specificProfile = MainApp.getConfigBuilder().getProfile(); specificProfile = MainApp.getConfigBuilder().getProfile();
else else
specificProfile = profile.getSpecificProfile(selectedAlternativeProfile); specificProfile = profileStore.getSpecificProfile(selectedAlternativeProfile);
// Entered values // Entered values
Double c_bg = SafeParse.stringToDouble(editBg.getText()); Double c_bg = SafeParse.stringToDouble(editBg.getText());

View file

@ -61,7 +61,7 @@ public class Notification {
public static final int BASAL_PROFILE_NOT_ALIGNED_TO_HOURS = 30; public static final int BASAL_PROFILE_NOT_ALIGNED_TO_HOURS = 30;
public static final int ZERO_VALUE_IN_PROFILE = 31; public static final int ZERO_VALUE_IN_PROFILE = 31;
public static final int PROFILE_SWITCH_MISSING = 32; public static final int PROFILE_SWITCH_MISSING = 32;
public static final int NOT_ENG_MODE_OR_RELEASE = 33;
public int id; public int id;
public Date date; public Date date;

View file

@ -114,6 +114,12 @@ public class SensitivityOref0Plugin implements PluginBase, SensitivityInterface
int hoursForDetection = SP.getInt(R.string.key_openapsama_autosens_period, defaultHours); int hoursForDetection = SP.getInt(R.string.key_openapsama_autosens_period, defaultHours);
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
Profile profile = MainApp.getConfigBuilder().getProfile();
if (profile == null) {
log.debug("No profile");
return new AutosensResult();
}
if (autosensDataTable == null || autosensDataTable.size() < 4) { if (autosensDataTable == null || autosensDataTable.size() < 4) {
log.debug("No autosens data available"); log.debug("No autosens data available");
@ -159,8 +165,6 @@ public class SensitivityOref0Plugin implements PluginBase, SensitivityInterface
Double[] deviations = new Double[deviationsArray.size()]; Double[] deviations = new Double[deviationsArray.size()];
deviations = deviationsArray.toArray(deviations); deviations = deviationsArray.toArray(deviations);
Profile profile = MainApp.getConfigBuilder().getProfile();
double sens = profile.getIsf(); double sens = profile.getIsf();
double ratio = 1; double ratio = 1;

View file

@ -142,16 +142,18 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
} }
private static void initializeTreatmentData() { private static void initializeTreatmentData() {
// Treatments double dia = Constants.defaultDIA;
double dia = MainApp.getConfigBuilder() == null ? Constants.defaultDIA : MainApp.getConfigBuilder().getProfile().getDia(); if (MainApp.getConfigBuilder() != null && MainApp.getConfigBuilder().getProfile() != null)
dia = MainApp.getConfigBuilder().getProfile().getDia();
long fromMills = (long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia)); long fromMills = (long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia));
treatments = MainApp.getDbHelper().getTreatmentDataFromTime(fromMills, false); treatments = MainApp.getDbHelper().getTreatmentDataFromTime(fromMills, false);
} }
private static void initializeTempBasalData() { private static void initializeTempBasalData() {
// Treatments double dia = Constants.defaultDIA;
double dia = MainApp.getConfigBuilder() == null ? Constants.defaultDIA : MainApp.getConfigBuilder().getProfile().getDia(); if (MainApp.getConfigBuilder() != null && MainApp.getConfigBuilder().getProfile() != null)
dia = MainApp.getConfigBuilder().getProfile().getDia();
long fromMills = (long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia)); long fromMills = (long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia));
tempBasals.reset().add(MainApp.getDbHelper().getTemporaryBasalsDataFromTime(fromMills, false)); tempBasals.reset().add(MainApp.getDbHelper().getTemporaryBasalsDataFromTime(fromMills, false));
@ -159,8 +161,9 @@ public class TreatmentsPlugin implements PluginBase, TreatmentsInterface {
} }
private static void initializeExtendedBolusData() { private static void initializeExtendedBolusData() {
// Treatments double dia = Constants.defaultDIA;
double dia = MainApp.getConfigBuilder() == null ? Constants.defaultDIA : MainApp.getConfigBuilder().getProfile().getDia(); if (MainApp.getConfigBuilder() != null && MainApp.getConfigBuilder().getProfile() != null)
dia = MainApp.getConfigBuilder().getProfile().getDia();
long fromMills = (long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia)); long fromMills = (long) (System.currentTimeMillis() - 60 * 60 * 1000L * (24 + dia));
extendedBoluses.reset().add(MainApp.getDbHelper().getExtendedBolusDataFromTime(fromMills, false)); extendedBoluses.reset().add(MainApp.getDbHelper().getExtendedBolusDataFromTime(fromMills, false));

View file

@ -389,8 +389,10 @@ public class WatchUpdaterService extends WearableListenerService implements
if (tb1 != null) { if (tb1 != null) {
tb_before = beginBasalValue; tb_before = beginBasalValue;
Profile profileTB = MainApp.getConfigBuilder().getProfile(runningTime); Profile profileTB = MainApp.getConfigBuilder().getProfile(runningTime);
tb_amount = tb1.tempBasalConvertedToAbsolute(runningTime, profileTB); if (profileTB != null) {
tb_start = runningTime; tb_amount = tb1.tempBasalConvertedToAbsolute(runningTime, profileTB);
tb_start = runningTime;
}
} }

View file

@ -309,6 +309,14 @@ public class CommandQueue {
} }
} }
if (!MainApp.isEngineeringModeOrRelease()) {
Notification notification = new Notification(Notification.NOT_ENG_MODE_OR_RELEASE, MainApp.sResources.getString(R.string.not_eng_mode_or_release), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
if (callback != null)
callback.result(new PumpEnactResult().success(false).comment(MainApp.sResources.getString(R.string.not_eng_mode_or_release))).run();
return false;
}
// Compare with pump limits // Compare with pump limits
Profile.BasalValue[] basalValues = profile.getBasalValues(); Profile.BasalValue[] basalValues = profile.getBasalValues();
PumpInterface pump = ConfigBuilderPlugin.getActivePump(); PumpInterface pump = ConfigBuilderPlugin.getActivePump();

View file

@ -11,6 +11,17 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<TextView
android:id="@+id/historybrowse_noprofile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="@string/noprofileset"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="@android:color/holo_red_light"
android:textStyle="bold"
android:visibility="gone" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View file

@ -234,7 +234,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingLeft="5dp" android:paddingLeft="5dp"
android:text="23 g" /> android:text="" />
</LinearLayout> </LinearLayout>

View file

@ -313,7 +313,7 @@
android:id="@+id/overview_cob" android:id="@+id/overview_cob"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="23 g" android:text=""
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:textSize="14sp" /> android:textSize="14sp" />

View file

@ -366,7 +366,7 @@
android:gravity="start" android:gravity="start"
android:orientation="horizontal" android:orientation="horizontal"
android:paddingLeft="5dp" android:paddingLeft="5dp"
android:text="23 g" android:text=""
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:textSize="14sp" /> android:textSize="14sp" />

View file

@ -228,7 +228,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingLeft="5dp" android:paddingLeft="5dp"
android:text="23 g" /> android:text="" />
</LinearLayout> </LinearLayout>

View file

@ -991,6 +991,9 @@
<string name="overview_show_cob">Carbs On Board</string> <string name="overview_show_cob">Carbs On Board</string>
<string name="overview_show_iob">Insulin On Board</string> <string name="overview_show_iob">Insulin On Board</string>
<string name="overview_show_basals">Basals</string> <string name="overview_show_basals">Basals</string>
<string name="closed_loop_disabled_on_dev_branch">Running dev version. Closed loop is disabled</string>
<string name="engineering_mode_enabled">Engineering mode enabled</string>
<string name="not_eng_mode_or_release">Engineering mode not enabled and not on release branch</string>
<string name="pump_basebasalrate">%.2f U/h</string> <string name="pump_basebasalrate">%.2f U/h</string>
<string name="combo_actvity_reading_basal_profile">Reading basal profile</string> <string name="combo_actvity_reading_basal_profile">Reading basal profile</string>
<string name="combo_bolus_rejected_due_to_pump_history_change">The pump history has changed after the bolus calculation was performed. The bolus was not delivered. Please recalculate if a bolus is still needed. If the same bolus amount is required, please wait two minutes since boluses with the same amount are blocked when requested with less than two minutes between them for safety (regardless of whether they were administered or not).</string> <string name="combo_bolus_rejected_due_to_pump_history_change">The pump history has changed after the bolus calculation was performed. The bolus was not delivered. Please recalculate if a bolus is still needed. If the same bolus amount is required, please wait two minutes since boluses with the same amount are blocked when requested with less than two minutes between them for safety (regardless of whether they were administered or not).</string>

View file

@ -1,7 +1,6 @@
package info.nightscout.androidaps.queue; package info.nightscout.androidaps.queue;
import android.content.Context; import android.content.Context;
import android.text.Html;
import com.squareup.otto.Bus; import com.squareup.otto.Bus;
import com.squareup.otto.ThreadEnforcer; import com.squareup.otto.ThreadEnforcer;
@ -116,6 +115,7 @@ public class CommandQueueTest extends CommandQueue {
PowerMockito.mockStatic(MainApp.class); PowerMockito.mockStatic(MainApp.class);
MainApp mainApp = mock(MainApp.class); MainApp mainApp = mock(MainApp.class);
when(MainApp.getConfigBuilder()).thenReturn(configBuilderPlugin); when(MainApp.getConfigBuilder()).thenReturn(configBuilderPlugin);
when(MainApp.isEngineeringModeOrRelease()).thenReturn(true);
when(MainApp.instance()).thenReturn(mainApp); when(MainApp.instance()).thenReturn(mainApp);
PowerMockito.mockStatic(ToastUtils.class); PowerMockito.mockStatic(ToastUtils.class);