diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index 69b6efc1e..baabf5d19 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -88,18 +88,11 @@ public class GBApplication extends Application { public static final String ACTION_QUIT = "nodomain.freeyourgadget.gadgetbridge.gbapplication.action.quit"; - - private static GBApplication app; - private static Logging logging = new Logging() { @Override protected String createLogDirectory() throws IOException { - if (GBEnvironment.env().isLocalTest()) { - return System.getProperty(Logging.PROP_LOGFILES_DIR); - } else { - File dir = FileUtils.getExternalFilesDir(); - return dir.getAbsolutePath(); - } + File dir = FileUtils.getExternalFilesDir(); + return dir.getAbsolutePath(); } }; @@ -117,17 +110,12 @@ public class GBApplication extends Application { // don't do anything here, add it to onCreate instead } - public static Logging getLogging() { - return logging; - } - protected DeviceService createDeviceService() { return new GBDeviceService(this); } @Override public void onCreate() { - app = this; super.onCreate(); if (lockHandler != null) { @@ -149,12 +137,9 @@ public class GBApplication extends Application { setupExceptionHandler(); - if (!GBEnvironment.isEnvironmentSetup()) { - GBEnvironment.setupEnvironment(GBEnvironment.createDeviceEnvironment()); - // setup db after the environment is set up, but don't do it in test mode - // in test mode, it's done individually, see TestBase - setupDatabase(); - } + GB.environment = GBEnvironment.createDeviceEnvironment(); + + setupDatabase(this); deviceManager = new DeviceManager(this); @@ -210,14 +195,8 @@ public class GBApplication extends Application { return prefs.getBoolean("minimize_priority", false); } - public void setupDatabase() { - DaoMaster.OpenHelper helper; - GBEnvironment env = GBEnvironment.env(); - if (env.isTest()) { - helper = new DaoMaster.DevOpenHelper(this, null, null); - } else { - helper = new DBOpenHelper(this, DATABASE_NAME, null); - } + static void setupDatabase(Context context) { + DBOpenHelper helper = new DBOpenHelper(context, DATABASE_NAME, null); SQLiteDatabase db = helper.getWritableDatabase(); DaoMaster daoMaster = new DaoMaster(db); if (lockHandler == null) { @@ -492,8 +471,4 @@ public class GBApplication extends Application { public DeviceManager getDeviceManager() { return deviceManager; } - - public static GBApplication app() { - return app; - } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBEnvironment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBEnvironment.java index 571a0bbc0..315cdddeb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBEnvironment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBEnvironment.java @@ -20,10 +20,6 @@ package nodomain.freeyourgadget.gadgetbridge; * Some more or less useful utility methods to aid local (non-device) testing. */ public class GBEnvironment { -// DO NOT USE A LOGGER HERE. Will break LoggingTest! -// private static final Logger LOG = LoggerFactory.getLogger(GBEnvironment.class); - - private static GBEnvironment environment; private boolean localTest; private boolean deviceTest; @@ -45,15 +41,4 @@ public class GBEnvironment { return localTest; } - public static synchronized GBEnvironment env() { - return environment; - } - - static synchronized boolean isEnvironmentSetup() { - return environment != null; - } - - public synchronized static void setupEnvironment(GBEnvironment env) { - environment = env; - } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/LockHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/LockHandler.java index d5aff21ed..1d72efecb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/LockHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/LockHandler.java @@ -20,6 +20,7 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; +import nodomain.freeyourgadget.gadgetbridge.database.DBOpenHelper; import nodomain.freeyourgadget.gadgetbridge.entities.DaoMaster; import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; @@ -35,7 +36,7 @@ public class LockHandler implements DBHandler { public LockHandler() { } - public void init(DaoMaster daoMaster, DaoMaster.OpenHelper helper) { + public void init(DaoMaster daoMaster, DBOpenHelper helper) { if (isValid()) { throw new IllegalStateException("DB must be closed before initializing it again"); } @@ -81,7 +82,7 @@ public class LockHandler implements DBHandler { throw new IllegalStateException("session must be null"); } // this will create completely new db instances and in turn update this handler through #init() - GBApplication.app().setupDatabase(); + GBApplication.setupDatabase(GBApplication.getContext()); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/CalendarReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/CalendarReceiver.java index 5d5382483..62bfa003a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/CalendarReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/CalendarReceiver.java @@ -34,7 +34,6 @@ import java.util.List; import de.greenrobot.dao.query.QueryBuilder; import nodomain.freeyourgadget.gadgetbridge.GBApplication; -import nodomain.freeyourgadget.gadgetbridge.GBException; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.entities.CalendarSyncState; @@ -98,76 +97,76 @@ public class CalendarReceiver extends BroadcastReceiver { } public void syncCalendar(List eventList) { - try (DBHandler dbHandler = GBApplication.acquireDB()) { - DaoSession session = dbHandler.getDaoSession(); - syncCalendar(eventList, session); - } catch (Exception e1) { - GB.toast("Database Error while syncing Calendar", Toast.LENGTH_SHORT, GB.ERROR); - } - } - - public void syncCalendar(List eventList, DaoSession session) { LOG.info("Syncing with calendar."); Hashtable eventTable = new Hashtable<>(); - Long deviceId = DBHelper.getDevice(mGBDevice, session).getId(); - QueryBuilder qb = session.getCalendarSyncStateDao().queryBuilder(); + + try (DBHandler dbHandler = GBApplication.acquireDB()) { + DaoSession session = dbHandler.getDaoSession(); + Long deviceId = DBHelper.getDevice(mGBDevice, session).getId(); + + QueryBuilder qb = session.getCalendarSyncStateDao().queryBuilder(); - for (CalendarEvents.CalendarEvent e : eventList) { - long id = e.getId(); - eventTable.put(id, e); - if (!eventState.containsKey(e.getId())) { - qb = session.getCalendarSyncStateDao().queryBuilder(); + for (CalendarEvents.CalendarEvent e : eventList) { + long id = e.getId(); + eventTable.put(id, e); + if (!eventState.containsKey(e.getId())) { + qb = session.getCalendarSyncStateDao().queryBuilder(); - CalendarSyncState calendarSyncState = qb.where(qb.and(CalendarSyncStateDao.Properties.DeviceId.eq(deviceId), CalendarSyncStateDao.Properties.CalendarEntryId.eq(id))) - .build().unique(); - if (calendarSyncState == null) { - eventState.put(id, new EventSyncState(e, EventState.NOT_SYNCED)); - LOG.info("event id=" + id + " is yet unknown to device id=" + deviceId); - } else if (calendarSyncState.getHash() == e.hashCode()) { - eventState.put(id, new EventSyncState(e, EventState.SYNCED)); - LOG.info("event id=" + id + " is up to date on device id=" + deviceId); - } - else { - eventState.put(id, new EventSyncState(e, EventState.NEEDS_UPDATE)); - LOG.info("event id=" + id + " is not up to date on device id=" + deviceId); - } - } - } - - // add all missing calendar ids on the device to sync status (so that they are deleted later) - List CalendarSyncStateList = qb.where(CalendarSyncStateDao.Properties.DeviceId.eq(deviceId)).build().list(); - for (CalendarSyncState CalendarSyncState : CalendarSyncStateList) { - if (!eventState.containsKey(CalendarSyncState.getCalendarEntryId())) { - eventState.put(CalendarSyncState.getCalendarEntryId(), new EventSyncState(null, EventState.NEEDS_DELETE)); - LOG.info("insert null event for orphanded calendar id=" + CalendarSyncState.getCalendarEntryId() + " for device=" + mGBDevice.getName()); - } - } - - Enumeration ids = eventState.keys(); - while (ids.hasMoreElements()) { - qb = session.getCalendarSyncStateDao().queryBuilder(); - Long i = ids.nextElement(); - EventSyncState es = eventState.get(i); - if (eventTable.containsKey(i)) { - if (es.getState() == EventState.SYNCED) { - if (!es.getEvent().equals(eventTable.get(i))) { - eventState.put(i, new EventSyncState(eventTable.get(i), EventState.NEEDS_UPDATE)); + CalendarSyncState calendarSyncState = qb.where(qb.and(CalendarSyncStateDao.Properties.DeviceId.eq(deviceId), CalendarSyncStateDao.Properties.CalendarEntryId.eq(id))) + .build().unique(); + if (calendarSyncState == null) { + eventState.put(id, new EventSyncState(e, EventState.NOT_SYNCED)); + LOG.info("event id=" + id + " is yet unknown to device id=" + deviceId); + } else if (calendarSyncState.getHash() == e.hashCode()) { + eventState.put(id, new EventSyncState(e, EventState.SYNCED)); + LOG.info("event id=" + id + " is up to date on device id=" + deviceId); + } + else { + eventState.put(id, new EventSyncState(e, EventState.NEEDS_UPDATE)); + LOG.info("event id=" + id + " is not up to date on device id=" + deviceId); } } - } else { - if (es.getState() == EventState.NOT_SYNCED) { - // delete for current device only - qb.where(qb.and(CalendarSyncStateDao.Properties.DeviceId.eq(deviceId), CalendarSyncStateDao.Properties.CalendarEntryId.eq(i))) - .buildDelete().executeDeleteWithoutDetachingEntities(); - eventState.remove(i); - } else { - es.setState(EventState.NEEDS_DELETE); - eventState.put(i, es); + } + + // add all missing calendar ids on the device to sync status (so that they are deleted later) + List CalendarSyncStateList = qb.where(CalendarSyncStateDao.Properties.DeviceId.eq(deviceId)).build().list(); + for (CalendarSyncState CalendarSyncState : CalendarSyncStateList) { + if (!eventState.containsKey(CalendarSyncState.getCalendarEntryId())) { + eventState.put(CalendarSyncState.getCalendarEntryId(), new EventSyncState(null, EventState.NEEDS_DELETE)); + LOG.info("insert null event for orphanded calendar id=" + CalendarSyncState.getCalendarEntryId() + " for device=" + mGBDevice.getName()); } } - updateEvents(deviceId, session); + + Enumeration ids = eventState.keys(); + while (ids.hasMoreElements()) { + qb = session.getCalendarSyncStateDao().queryBuilder(); + Long i = ids.nextElement(); + EventSyncState es = eventState.get(i); + if (eventTable.containsKey(i)) { + if (es.getState() == EventState.SYNCED) { + if (!es.getEvent().equals(eventTable.get(i))) { + eventState.put(i, new EventSyncState(eventTable.get(i), EventState.NEEDS_UPDATE)); + } + } + } else { + if (es.getState() == EventState.NOT_SYNCED) { + // delete for current device only + qb.where(qb.and(CalendarSyncStateDao.Properties.DeviceId.eq(deviceId), CalendarSyncStateDao.Properties.CalendarEntryId.eq(i))) + .buildDelete().executeDeleteWithoutDetachingEntities(); + eventState.remove(i); + } else { + es.setState(EventState.NEEDS_DELETE); + eventState.put(i, es); + } + } + updateEvents(deviceId, session); + } + } catch (Exception e) { + e.printStackTrace(); + GB.toast("Database Error while syncing Calendar", Toast.LENGTH_SHORT, GB.ERROR); } + } private void updateEvents(Long deviceId, DaoSession session) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java index 117887341..ba6150f01 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java @@ -38,7 +38,6 @@ import java.util.ArrayList; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.GBApplication; -import nodomain.freeyourgadget.gadgetbridge.GBEnvironment; public class FileUtils { // Don't use slf4j here -- would be a bootstrapping problem @@ -210,11 +209,9 @@ public class FileUtils { // the first directory is also the primary external storage, i.e. the same as Environment.getExternalFilesDir() // TODO: check the mount state of *all* dirs when switching to later API level - if (!GBEnvironment.env().isLocalTest()) { // don't do this with robolectric - if (i == 0 && !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { - GB.log("ignoring unmounted external storage dir: " + dir, GB.INFO, null); - continue; - } + if (i == 0 && !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { + GB.log("ignoring unmounted external storage dir: " + dir, GB.INFO, null); + continue; } result.add(dir); // add last } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java index 1a75cd7f0..42d4fd41d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java @@ -60,9 +60,10 @@ public class GB { public static final String DISPLAY_MESSAGE_MESSAGE = "message"; public static final String DISPLAY_MESSAGE_DURATION = "duration"; public static final String DISPLAY_MESSAGE_SEVERITY = "severity"; + public static GBEnvironment environment; public static Notification createNotification(String text, boolean connected, Context context) { - if (GBEnvironment.env().isLocalTest()) { + if (env().isLocalTest()) { return null; } Intent notificationIntent = new Intent(context, ControlCenterv2.class); @@ -226,7 +227,7 @@ public class GB { */ public static void toast(final Context context, final String message, final int displayTime, final int severity, final Throwable ex) { log(message, severity, ex); // log immediately, not delayed - if (GBEnvironment.env().isLocalTest()) { + if (env().isLocalTest()) { return; } Looper mainLooper = Looper.getMainLooper(); @@ -357,7 +358,7 @@ public class GB { } public static void updateBatteryNotification(String text, String bigText, Context context) { - if (GBEnvironment.env().isLocalTest()) { + if (env().isLocalTest()) { return; } Notification notification = createBatteryNotification(text, bigText, context); @@ -368,6 +369,10 @@ public class GB { removeNotification(NOTIFICATION_ID_LOW_BATTERY, context); } + public static GBEnvironment env() { + return environment; + } + public static void assertThat(boolean condition, String errorMessage) { if (!condition) { throw new AssertionError(errorMessage); diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/CalendarEventTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/CalendarEventTest.java index 05b57a676..bd8c6919e 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/CalendarEventTest.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/CalendarEventTest.java @@ -5,9 +5,7 @@ import org.junit.Test; import java.util.ArrayList; import java.util.List; -import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.entities.CalendarSyncStateDao; -import nodomain.freeyourgadget.gadgetbridge.entities.Device; import nodomain.freeyourgadget.gadgetbridge.externalevents.CalendarReceiver; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.CalendarEvents; diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/LoggingTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/LoggingTest.java index 25adcfea3..bd586669c 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/LoggingTest.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/LoggingTest.java @@ -6,8 +6,8 @@ import org.junit.After; import org.junit.Test; import java.io.File; +import java.io.IOException; -import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.Logging; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; @@ -25,12 +25,16 @@ public class LoggingTest extends TestBase { public LoggingTest() throws Exception { } - private Logging logging = GBApplication.getLogging(); + private Logging logging = new Logging() { + @Override + protected String createLogDirectory() throws IOException { + return logFilesDir.getAbsolutePath(); + } + }; @Override @After - public void tearDown() throws Exception { - super.tearDown(); + public void tearDown() { assertTrue(FileUtils.deleteRecursively(getLogFilesDir())); } diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/TestBase.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/TestBase.java index 636f1077c..298c1c382 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/TestBase.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/TestBase.java @@ -1,6 +1,7 @@ package nodomain.freeyourgadget.gadgetbridge.test; import android.content.Context; +import android.database.sqlite.SQLiteDatabase; import org.junit.After; import org.junit.Before; @@ -15,9 +16,9 @@ import java.io.File; import ch.qos.logback.classic.util.ContextInitializer; import nodomain.freeyourgadget.gadgetbridge.BuildConfig; import nodomain.freeyourgadget.gadgetbridge.GBApplication; -import nodomain.freeyourgadget.gadgetbridge.GBEnvironment; import nodomain.freeyourgadget.gadgetbridge.Logging; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; +import nodomain.freeyourgadget.gadgetbridge.entities.DaoMaster; import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; @@ -45,10 +46,9 @@ public abstract class TestBase { // Make sure logging is set up for all testcases, so that we can debug problems @BeforeClass public static void setupSuite() throws Exception { - GBEnvironment.setupEnvironment(GBEnvironment.createLocalTestEnvironment()); - // print everything going to android.util.Log to System.out System.setProperty("robolectric.logging", "stdout"); +// ShadowLog.stream = System.out; // properties might be preconfigured in build.gradle because of test ordering problems String logDir = System.getProperty(Logging.PROP_LOGFILES_DIR); @@ -69,19 +69,20 @@ public abstract class TestBase { @Before public void setUp() throws Exception { - app = (GBApplication) RuntimeEnvironment.application; assertNotNull(app); assertNotNull(getContext()); - app.setupDatabase(); - dbHandler = GBApplication.acquireDB(); - daoSession = dbHandler.getDaoSession(); +// doesn't work with Robolectric yet +// dbHandler = GBApplication.acquireDB(); +// daoSession = dbHandler.getDaoSession(); + DaoMaster.DevOpenHelper openHelper = new DaoMaster.DevOpenHelper(app, null, null); + SQLiteDatabase db = openHelper.getWritableDatabase(); + daoSession = new DaoMaster(db).newSession(); assertNotNull(daoSession); } @After public void tearDown() throws Exception { - dbHandler.closeDb(); - GBApplication.releaseDB(); +// GBApplication.releaseDB(); } protected GBDevice createDummyGDevice(String macAddress) {