diff --git a/app/src/androidTest/java/com/etesync/syncadapter/model/CollectionInfoTest.java b/app/src/androidTest/java/com/etesync/syncadapter/model/CollectionInfoTest.java
deleted file mode 100644
index 0edcaaa9..00000000
--- a/app/src/androidTest/java/com/etesync/syncadapter/model/CollectionInfoTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the GNU Public License v3.0
- * which accompanies this distribution, and is available at
- * http://www.gnu.org/licenses/gpl.html
- */
-
-package com.etesync.syncadapter.model;
-
-import android.content.ContentValues;
-
-import org.junit.Test;
-
-import com.etesync.syncadapter.model.ServiceDB.Collections;
-import okhttp3.mockwebserver.MockWebServer;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-public class CollectionInfoTest {
-
- MockWebServer server = new MockWebServer();
-
- @Test
- public void testFromDB() {
- ContentValues values = new ContentValues();
- values.put(Collections.ID, 1);
- values.put(Collections.SERVICE_ID, 1);
- values.put(Collections.URL, "http://example.com");
- values.put(Collections.READ_ONLY, 1);
- values.put(Collections.DISPLAY_NAME, "display name");
- values.put(Collections.DESCRIPTION, "description");
- values.put(Collections.COLOR, 0xFFFF0000);
- values.put(Collections.TIME_ZONE, "tzdata");
- values.put(Collections.SUPPORTS_VEVENT, 1);
- values.put(Collections.SUPPORTS_VTODO, 1);
- values.put(Collections.SYNC, 1);
-
- CollectionInfo info = CollectionInfo.fromDB(values);
- assertEquals(1, info.id);
- assertEquals(1, (long)info.serviceID);
- assertEquals("http://example.com", info.url);
- assertTrue(info.readOnly);
- assertEquals("display name", info.displayName);
- assertEquals("description", info.description);
- assertEquals(0xFFFF0000, (int)info.color);
- assertEquals("tzdata", info.timeZone);
- assertTrue(info.supportsVEVENT);
- assertTrue(info.supportsVTODO);
- assertTrue(info.selected);
- }
-
-}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 33ecec35..c47e5f92 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,6 +60,15 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/etesync/syncadapter/App.java b/app/src/main/java/com/etesync/syncadapter/App.java
index aeaae5f1..1efee55d 100644
--- a/app/src/main/java/com/etesync/syncadapter/App.java
+++ b/app/src/main/java/com/etesync/syncadapter/App.java
@@ -8,11 +8,19 @@
package com.etesync.syncadapter;
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Application;
import android.content.BroadcastReceiver;
+import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@@ -27,6 +35,8 @@ import android.util.Log;
import com.etesync.syncadapter.log.LogcatHandler;
import com.etesync.syncadapter.log.PlainTextFormatter;
+import com.etesync.syncadapter.model.CollectionInfo;
+import com.etesync.syncadapter.model.JournalEntity;
import com.etesync.syncadapter.model.Models;
import com.etesync.syncadapter.model.ServiceDB;
import com.etesync.syncadapter.model.Settings;
@@ -35,6 +45,8 @@ import org.apache.commons.lang3.time.DateFormatUtils;
import java.io.File;
import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
@@ -207,4 +219,56 @@ public class App extends Application {
}
return dataStore;
}
+
+ // update from previous account settings
+
+ private final static String PREF_VERSION = "version";
+
+ private void update(int fromVersion) {
+ App.log.info("Updating from version " + fromVersion + " to " + BuildConfig.VERSION_CODE);
+
+ if (fromVersion < 6) {
+ EntityDataStore data = this.getData();
+
+ ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(this);
+
+ List collections = readCollections(dbHelper);
+ for (CollectionInfo info : collections) {
+ JournalEntity journalEntity = new JournalEntity(info);
+ data.insert(journalEntity);
+ }
+
+ @Cleanup SQLiteDatabase db = dbHelper.getWritableDatabase();
+ db.delete(ServiceDB.Collections._TABLE, null, null);
+ }
+ }
+
+ public static class AppUpdatedReceiver extends BroadcastReceiver {
+
+ @Override
+ @SuppressLint("UnsafeProtectedBroadcastReceiver,MissingPermission")
+ public void onReceive(Context context, Intent intent) {
+ App.log.info("EteSync was updated, checking for app version");
+
+ App app = (App) context.getApplicationContext();
+ SharedPreferences prefs = app.getSharedPreferences("app", Context.MODE_PRIVATE);
+ int fromVersion = prefs.getInt(PREF_VERSION, 1);
+ app.update(fromVersion);
+ prefs.edit().putInt(PREF_VERSION, BuildConfig.VERSION_CODE).apply();
+ }
+
+ }
+
+ @NonNull
+ private List readCollections(ServiceDB.OpenHelper dbHelper) {
+ @Cleanup SQLiteDatabase db = dbHelper.getWritableDatabase();
+ List collections = new LinkedList<>();
+ @Cleanup Cursor cursor = db.query(ServiceDB.Collections._TABLE, null, null, null, null, null, null);
+ while (cursor.moveToNext()) {
+ ContentValues values = new ContentValues();
+ DatabaseUtils.cursorRowToContentValues(cursor, values);
+ collections.add(CollectionInfo.fromDB(values));
+ }
+ return collections;
+ }
}
diff --git a/app/src/main/java/com/etesync/syncadapter/model/CollectionInfo.java b/app/src/main/java/com/etesync/syncadapter/model/CollectionInfo.java
index 2d7aa500..13326a98 100644
--- a/app/src/main/java/com/etesync/syncadapter/model/CollectionInfo.java
+++ b/app/src/main/java/com/etesync/syncadapter/model/CollectionInfo.java
@@ -93,26 +93,6 @@ public class CollectionInfo implements Serializable {
return info;
}
- public ContentValues toDB() {
- ContentValues values = new ContentValues();
- // Collections.SERVICE_ID is never changed
-
- values.put(Collections.URL, url);
- values.put(Collections.READ_ONLY, readOnly ? 1 : 0);
- values.put(Collections.DISPLAY_NAME, displayName);
- values.put(Collections.DESCRIPTION, description);
- values.put(Collections.COLOR, color);
-
- values.put(Collections.TIME_ZONE, timeZone);
- if (supportsVEVENT != null)
- values.put(Collections.SUPPORTS_VEVENT, supportsVEVENT ? 1 : 0);
- if (supportsVTODO != null)
- values.put(Collections.SUPPORTS_VTODO, supportsVTODO ? 1 : 0);
-
- values.put(Collections.SYNC, selected ? 1 : 0);
- return values;
- }
-
public static CollectionInfo fromJson(String json) {
return new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create().fromJson(json, CollectionInfo.class);
}
diff --git a/app/src/main/java/com/etesync/syncadapter/model/JournalModel.java b/app/src/main/java/com/etesync/syncadapter/model/JournalModel.java
index 78d0cd89..9ce224cf 100644
--- a/app/src/main/java/com/etesync/syncadapter/model/JournalModel.java
+++ b/app/src/main/java/com/etesync/syncadapter/model/JournalModel.java
@@ -1,16 +1,21 @@
package com.etesync.syncadapter.model;
-import io.requery.CascadeAction;
+import java.util.LinkedList;
+import java.util.List;
+
import io.requery.Column;
+import io.requery.Convert;
+import io.requery.Converter;
import io.requery.Entity;
import io.requery.ForeignKey;
import io.requery.Generated;
import io.requery.Index;
import io.requery.Key;
import io.requery.ManyToOne;
-import io.requery.OneToMany;
-import io.requery.OneToOne;
+import io.requery.Persistable;
+import io.requery.PostLoad;
import io.requery.ReferentialAction;
+import io.requery.sql.EntityDataStore;
public class JournalModel {
@Entity
@@ -21,6 +26,57 @@ public class JournalModel {
@Column(length = 64, unique = true, nullable = false)
String uid;
+
+ @Convert(CollectionInfoConverter.class)
+ CollectionInfo info;
+
+ long service;
+
+ boolean deleted;
+
+ @PostLoad
+ void afterLoad() {
+ this.info.serviceID = service;
+ this.info.url = uid;
+ }
+
+ public Journal() {
+ this.deleted = false;
+ }
+
+ public Journal(CollectionInfo info) {
+ this();
+ this.info = info;
+ this.uid = info.url;
+ this.service = info.serviceID;
+ }
+
+ public static List getCollections(EntityDataStore data, long service) {
+ List ret = new LinkedList<>();
+
+ List journals = data.select(JournalEntity.class).where(JournalEntity.SERVICE.eq(service).and(JournalEntity.DELETED.eq(false))).get().toList();
+ for (JournalEntity journal : journals) {
+ // FIXME: For some reason this isn't always being called, manually do it here.
+ journal.afterLoad();
+ ret.add(journal.getInfo());
+ }
+
+ return ret;
+ }
+
+ public static JournalEntity fetch(EntityDataStore data, String url) {
+ return data.select(JournalEntity.class).where(JournalEntity.UID.eq(url)).limit(1).get().firstOrNull();
+ }
+
+ public static JournalEntity fetchOrCreate(EntityDataStore data, CollectionInfo collection) {
+ JournalEntity journalEntity = fetch(data, collection.url);
+ if (journalEntity == null) {
+ journalEntity = new JournalEntity(collection);
+ } else {
+ journalEntity.setInfo(collection);
+ }
+ return journalEntity;
+ }
}
@Entity
@@ -39,4 +95,31 @@ public class JournalModel {
@ManyToOne
Journal journal;
}
+
+ public static class CollectionInfoConverter implements Converter {
+ @Override
+ public Class getMappedType() {
+ return CollectionInfo.class;
+ }
+
+ @Override
+ public Class getPersistedType() {
+ return String.class;
+ }
+
+ @Override
+ public Integer getPersistedSize() {
+ return null;
+ }
+
+ @Override
+ public String convertToPersisted(CollectionInfo value) {
+ return value == null ? null : value.toJson();
+ }
+
+ @Override
+ public CollectionInfo convertToMapped(Class extends CollectionInfo> type, String value) {
+ return value == null ? null : CollectionInfo.fromJson(value);
+ }
+ }
}
diff --git a/app/src/main/java/com/etesync/syncadapter/model/ServiceDB.java b/app/src/main/java/com/etesync/syncadapter/model/ServiceDB.java
index 56923a25..b9dceea8 100644
--- a/app/src/main/java/com/etesync/syncadapter/model/ServiceDB.java
+++ b/app/src/main/java/com/etesync/syncadapter/model/ServiceDB.java
@@ -100,21 +100,6 @@ public class ServiceDB {
Services.SERVICE + " TEXT NOT NULL" +
")");
db.execSQL("CREATE UNIQUE INDEX services_account ON " + Services._TABLE + " (" + Services.ACCOUNT_NAME + "," + Services.SERVICE + ")");
-
- db.execSQL("CREATE TABLE " + Collections._TABLE + "(" +
- Collections.ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
- Collections.SERVICE_ID + " INTEGER NOT NULL REFERENCES " + Services._TABLE +" ON DELETE CASCADE," +
- Collections.URL + " TEXT NOT NULL," +
- Collections.READ_ONLY + " INTEGER DEFAULT 0 NOT NULL," +
- Collections.DISPLAY_NAME + " TEXT NULL," +
- Collections.DESCRIPTION + " TEXT NULL," +
- Collections.COLOR + " INTEGER NULL," +
- Collections.TIME_ZONE + " TEXT NULL," +
- Collections.SUPPORTS_VEVENT + " INTEGER NULL," +
- Collections.SUPPORTS_VTODO + " INTEGER NULL," +
- Collections.SYNC + " INTEGER DEFAULT 0 NOT NULL" +
- ")");
- db.execSQL("CREATE UNIQUE INDEX collections_service_url ON " + Collections._TABLE + "(" + Collections.SERVICE_ID + "," + Collections.URL + ")");
}
@Override
diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarsSyncAdapterService.java b/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarsSyncAdapterService.java
index 46a869b3..28d23c91 100644
--- a/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarsSyncAdapterService.java
+++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarsSyncAdapterService.java
@@ -11,21 +11,13 @@ import android.accounts.Account;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SyncResult;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.os.Bundle;
import android.provider.CalendarContract;
-import android.support.annotation.NonNull;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.logging.Level;
import com.etesync.syncadapter.AccountSettings;
import com.etesync.syncadapter.App;
@@ -34,13 +26,20 @@ import com.etesync.syncadapter.NotificationHelper;
import com.etesync.syncadapter.R;
import com.etesync.syncadapter.journalmanager.Exceptions;
import com.etesync.syncadapter.model.CollectionInfo;
+import com.etesync.syncadapter.model.JournalEntity;
import com.etesync.syncadapter.model.ServiceDB;
-import com.etesync.syncadapter.model.ServiceDB.Collections;
import com.etesync.syncadapter.model.ServiceDB.Services;
import com.etesync.syncadapter.resource.LocalCalendar;
import com.etesync.syncadapter.ui.DebugInfoActivity;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+
import at.bitfire.ical4android.CalendarStorageException;
-import lombok.Cleanup;
+import io.requery.Persistable;
+import io.requery.sql.EntityDataStore;
import okhttp3.HttpUrl;
import static com.etesync.syncadapter.Constants.KEY_ACCOUNT;
@@ -117,7 +116,12 @@ public class CalendarsSyncAdapterService extends SyncAdapterService {
ret = HttpUrl.get(settings.getUri());
- Map remote = remoteCalendars(db, service);
+ EntityDataStore data = ((App) getContext().getApplicationContext()).getData();
+ Map remote = new HashMap<>();
+ List remoteCollections = JournalEntity.getCollections(data, service);
+ for (CollectionInfo info : remoteCollections) {
+ remote.put(info.url, info);
+ }
LocalCalendar[] local = (LocalCalendar[])LocalCalendar.find(account, provider, LocalCalendar.Factory.INSTANCE, null, null);
@@ -151,23 +155,6 @@ public class CalendarsSyncAdapterService extends SyncAdapterService {
return ret;
}
-
- @NonNull
- private Map remoteCalendars(@NonNull SQLiteDatabase db, Long service) {
- Map collections = new LinkedHashMap<>();
- if (service != null) {
- @Cleanup Cursor cursor = db.query(Collections._TABLE, null,
- Collections.SERVICE_ID + "=? AND " + Collections.SUPPORTS_VEVENT + "!=0 AND " + Collections.SYNC,
- new String[]{String.valueOf(service)}, null, null, null);
- while (cursor.moveToNext()) {
- ContentValues values = new ContentValues();
- DatabaseUtils.cursorRowToContentValues(cursor, values);
- CollectionInfo info = CollectionInfo.fromDB(values);
- collections.put(info.url, info);
- }
- }
- return collections;
- }
}
}
diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncAdapterService.java b/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncAdapterService.java
index c0ab4be1..fc2f55cf 100644
--- a/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncAdapterService.java
+++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncAdapterService.java
@@ -11,18 +11,11 @@ import android.accounts.Account;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SyncResult;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import java.util.logging.Level;
import com.etesync.syncadapter.AccountSettings;
import com.etesync.syncadapter.App;
@@ -32,10 +25,14 @@ import com.etesync.syncadapter.NotificationHelper;
import com.etesync.syncadapter.R;
import com.etesync.syncadapter.journalmanager.Exceptions;
import com.etesync.syncadapter.model.CollectionInfo;
+import com.etesync.syncadapter.model.JournalEntity;
import com.etesync.syncadapter.model.ServiceDB;
-import com.etesync.syncadapter.model.ServiceDB.Collections;
import com.etesync.syncadapter.ui.DebugInfoActivity;
-import lombok.Cleanup;
+
+import java.util.logging.Level;
+
+import io.requery.Persistable;
+import io.requery.sql.EntityDataStore;
import okhttp3.HttpUrl;
import static com.etesync.syncadapter.Constants.KEY_ACCOUNT;
@@ -72,7 +69,8 @@ public class ContactsSyncAdapterService extends SyncAdapterService {
Long service = dbHelper.getService(db, account, ServiceDB.Services.SERVICE_CARDDAV);
if (service != null) {
HttpUrl principal = HttpUrl.get(settings.getUri());
- CollectionInfo info = remoteAddressBook(db, service);
+ EntityDataStore data = ((App) getContext().getApplicationContext()).getData();
+ CollectionInfo info = JournalEntity.getCollections(data, service).get(0);
try {
ContactsSyncManager syncManager = new ContactsSyncManager(getContext(), account, settings, extras, authority, provider, syncResult, principal, info);
syncManager.performSync();
@@ -103,18 +101,6 @@ public class ContactsSyncAdapterService extends SyncAdapterService {
App.log.info("Address book sync complete");
}
-
- @Nullable
- private CollectionInfo remoteAddressBook(@NonNull SQLiteDatabase db, long service) {
- @Cleanup Cursor c = db.query(Collections._TABLE, null,
- Collections.SERVICE_ID + "=? AND " + Collections.SYNC, new String[]{String.valueOf(service)}, null, null, null);
- if (c.moveToNext()) {
- ContentValues values = new ContentValues();
- DatabaseUtils.cursorRowToContentValues(c, values);
- return CollectionInfo.fromDB(values);
- } else
- return null;
- }
}
}
diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncAdapterService.java b/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncAdapterService.java
index 8962a635..694b5481 100644
--- a/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncAdapterService.java
+++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncAdapterService.java
@@ -32,6 +32,7 @@ import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
+import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
@@ -48,6 +49,7 @@ import com.etesync.syncadapter.journalmanager.Exceptions;
import com.etesync.syncadapter.journalmanager.JournalManager;
import com.etesync.syncadapter.model.CollectionInfo;
import com.etesync.syncadapter.model.JournalEntity;
+import com.etesync.syncadapter.model.JournalModel;
import com.etesync.syncadapter.model.ServiceDB;
import com.etesync.syncadapter.ui.PermissionsActivity;
@@ -185,35 +187,32 @@ public abstract class SyncAdapterService extends Service {
}
}
- @NonNull
- private Map readCollections(SQLiteDatabase db) {
- Long service = dbHelper.getService(db, account, serviceType.toString());
- Map collections = new LinkedHashMap<>();
- @Cleanup Cursor cursor = db.query(ServiceDB.Collections._TABLE, null, ServiceDB.Collections.SERVICE_ID + "=?", new String[]{String.valueOf(service)}, null, null, null);
- while (cursor.moveToNext()) {
- ContentValues values = new ContentValues();
- DatabaseUtils.cursorRowToContentValues(cursor, values);
- collections.put(values.getAsString(ServiceDB.Collections.URL), CollectionInfo.fromDB(values));
- }
- return collections;
- }
-
private void saveCollections(SQLiteDatabase db, Iterable collections) {
- EntityDataStore data = ((App) context.getApplicationContext()).getData();
Long service = dbHelper.getService(db, account, serviceType.toString());
- db.delete(ServiceDB.Collections._TABLE, ServiceDB.Collections.SERVICE_ID + "=?", new String[]{String.valueOf(service)});
- for (CollectionInfo collection : collections) {
- ContentValues values = collection.toDB();
- App.log.log(Level.FINE, "Saving collection", values);
- values.put(ServiceDB.Collections.SERVICE_ID, service);
- db.insertWithOnConflict(ServiceDB.Collections._TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
- JournalEntity journalEntity = data.select(JournalEntity.class).where(JournalEntity.UID.eq(collection.url)).limit(1).get().firstOrNull();
- if (journalEntity == null) {
- journalEntity = new JournalEntity();
- journalEntity.setUid(collection.url);
- data.insert(journalEntity);
- }
+ EntityDataStore data = ((App) context.getApplicationContext()).getData();
+ Map existing = new HashMap<>();
+ List existingList = JournalEntity.getCollections(data, service);
+ for (CollectionInfo info : existingList) {
+ existing.put(info.url, info);
+ }
+
+ for (CollectionInfo collection : collections) {
+ App.log.log(Level.FINE, "Saving collection", collection.url);
+
+ collection.serviceID = service;
+ JournalEntity journalEntity = JournalEntity.fetchOrCreate(data, collection);
+ data.upsert(journalEntity);
+
+ existing.remove(collection.url);
+ }
+
+ for (CollectionInfo collection : existing.values()) {
+ App.log.log(Level.FINE, "Deleting collection", collection.url);
+
+ JournalEntity journalEntity = data.select(JournalEntity.class).where(JournalEntity.UID.eq(collection.url)).limit(1).get().first();
+ journalEntity.setDeleted(true);
+ data.update(journalEntity);
}
}
}
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.java b/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.java
index f06459f4..f87930e0 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.java
@@ -18,7 +18,6 @@ import android.app.LoaderManager;
import android.content.AsyncTaskLoader;
import android.content.ComponentName;
import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -26,7 +25,6 @@ import android.content.Loader;
import android.content.ServiceConnection;
import android.content.SyncStatusObserver;
import android.database.Cursor;
-import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.drawable.Drawable;
import android.os.Build;
@@ -34,7 +32,6 @@ import android.os.Bundle;
import android.os.IBinder;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
-import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
@@ -64,11 +61,13 @@ import com.etesync.syncadapter.App;
import com.etesync.syncadapter.Constants;
import com.etesync.syncadapter.R;
import com.etesync.syncadapter.model.CollectionInfo;
-import com.etesync.syncadapter.model.ServiceDB.Collections;
+import com.etesync.syncadapter.model.JournalEntity;
import com.etesync.syncadapter.model.ServiceDB.OpenHelper;
import com.etesync.syncadapter.model.ServiceDB.Services;
import com.etesync.syncadapter.resource.LocalCalendar;
import at.bitfire.ical4android.TaskProvider;
+import io.requery.Persistable;
+import io.requery.sql.EntityDataStore;
import lombok.Cleanup;
import static android.content.ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;
@@ -331,6 +330,7 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
@Cleanup OpenHelper dbHelper = new OpenHelper(getContext());
SQLiteDatabase db = dbHelper.getReadableDatabase();
+ EntityDataStore data = ((App) getContext().getApplicationContext()).getData();
@Cleanup Cursor cursor = db.query(
Services._TABLE,
@@ -345,32 +345,18 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
info.carddav = new AccountInfo.ServiceInfo();
info.carddav.id = id;
info.carddav.refreshing = (davService != null && davService.isRefreshing(id)) || ContentResolver.isSyncActive(account, ContactsContract.AUTHORITY);
- info.carddav.collections = readCollections(db, id);
-
+ info.carddav.collections = JournalEntity.getCollections(data, id);
} else if (Services.SERVICE_CALDAV.equals(service)) {
info.caldav = new AccountInfo.ServiceInfo();
info.caldav.id = id;
info.caldav.refreshing = (davService != null && davService.isRefreshing(id)) ||
ContentResolver.isSyncActive(account, CalendarContract.AUTHORITY) ||
ContentResolver.isSyncActive(account, TaskProvider.ProviderName.OpenTasks.authority);
- info.caldav.collections = readCollections(db, id);
+ info.caldav.collections = JournalEntity.getCollections(data, id);
}
}
return info;
}
-
- private List readCollections(@NonNull SQLiteDatabase db, long service) {
- List collections = new LinkedList<>();
- @Cleanup Cursor cursor = db.query(Collections._TABLE, null, Collections.SERVICE_ID + "=?",
- new String[] { String.valueOf(service) }, null, null, Collections.SUPPORTS_VEVENT + " DESC," + Collections.DISPLAY_NAME);
- while (cursor.moveToNext()) {
- ContentValues values = new ContentValues();
- DatabaseUtils.cursorRowToContentValues(cursor, values);
- collections.add(CollectionInfo.fromDB(values));
- }
- return collections;
- }
-
}
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionFragment.java b/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionFragment.java
index 3927faf1..20686255 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionFragment.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionFragment.java
@@ -27,13 +27,18 @@ import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import com.etesync.syncadapter.AccountSettings;
+import com.etesync.syncadapter.App;
import com.etesync.syncadapter.HttpClient;
import com.etesync.syncadapter.InvalidAccountException;
import com.etesync.syncadapter.R;
import com.etesync.syncadapter.journalmanager.Exceptions;
import com.etesync.syncadapter.journalmanager.JournalManager;
import com.etesync.syncadapter.model.CollectionInfo;
+import com.etesync.syncadapter.model.JournalEntity;
import com.etesync.syncadapter.model.ServiceDB;
+
+import io.requery.Persistable;
+import io.requery.sql.EntityDataStore;
import lombok.Cleanup;
import okhttp3.HttpUrl;
@@ -161,9 +166,11 @@ public class CreateCollectionFragment extends DialogFragment implements LoaderMa
}
// 2. add collection to service
- ContentValues values = info.toDB();
- values.put(ServiceDB.Collections.SERVICE_ID, serviceID);
- db.insertWithOnConflict(ServiceDB.Collections._TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
+ EntityDataStore data = ((App) getContext().getApplicationContext()).getData();
+ info.serviceID = serviceID;
+ JournalEntity journalEntity = JournalEntity.fetchOrCreate(data, info);
+ data.upsert(journalEntity);
+
requestSync(authority);
} catch (IllegalStateException | Exceptions.HttpException e) {
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/DebugInfoActivity.java b/app/src/main/java/com/etesync/syncadapter/ui/DebugInfoActivity.java
index 347eab1c..306db17a 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/DebugInfoActivity.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/DebugInfoActivity.java
@@ -36,6 +36,7 @@ import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
+import java.util.List;
import java.util.logging.Level;
import com.etesync.syncadapter.AccountSettings;
@@ -45,7 +46,11 @@ import com.etesync.syncadapter.Constants;
import com.etesync.syncadapter.InvalidAccountException;
import com.etesync.syncadapter.R;
import com.etesync.syncadapter.journalmanager.Exceptions.HttpException;
+import com.etesync.syncadapter.model.JournalEntity;
import com.etesync.syncadapter.model.ServiceDB;
+
+import io.requery.Persistable;
+import io.requery.sql.EntityDataStore;
import lombok.Cleanup;
import static com.etesync.syncadapter.Constants.KEY_ACCOUNT;
@@ -240,6 +245,14 @@ public class DebugInfoActivity extends AppCompatActivity implements LoaderManage
dbHelper.dump(report);
report.append("\n");
+ report.append("JOURNALS DUMP\n");
+ EntityDataStore data = ((App) getContext().getApplicationContext()).getData();
+ List journals = data.select(JournalEntity.class).where(JournalEntity.DELETED.eq(false)).get().toList();
+ for (JournalEntity journal : journals) {
+ report.append(journal.toString() + "\n");
+ }
+ report.append("\n");
+
try {
report.append(
"SYSTEM INFORMATION\n" +
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/DeleteCollectionFragment.java b/app/src/main/java/com/etesync/syncadapter/ui/DeleteCollectionFragment.java
index d574e008..b53c5cdd 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/DeleteCollectionFragment.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/DeleteCollectionFragment.java
@@ -14,7 +14,6 @@ import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
-import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
@@ -25,13 +24,17 @@ import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import com.etesync.syncadapter.AccountSettings;
+import com.etesync.syncadapter.App;
import com.etesync.syncadapter.HttpClient;
import com.etesync.syncadapter.InvalidAccountException;
import com.etesync.syncadapter.R;
import com.etesync.syncadapter.journalmanager.Exceptions;
import com.etesync.syncadapter.journalmanager.JournalManager;
import com.etesync.syncadapter.model.CollectionInfo;
-import com.etesync.syncadapter.model.ServiceDB;
+import com.etesync.syncadapter.model.JournalEntity;
+
+import io.requery.Persistable;
+import io.requery.sql.EntityDataStore;
import okhttp3.HttpUrl;
public class DeleteCollectionFragment extends DialogFragment implements LoaderManager.LoaderCallbacks {
@@ -94,13 +97,11 @@ public class DeleteCollectionFragment extends DialogFragment implements LoaderMa
protected static class DeleteCollectionLoader extends AsyncTaskLoader {
final Account account;
final CollectionInfo collectionInfo;
- final ServiceDB.OpenHelper dbHelper;
public DeleteCollectionLoader(Context context, Account account, CollectionInfo collectionInfo) {
super(context);
this.account = account;
this.collectionInfo = collectionInfo;
- dbHelper = new ServiceDB.OpenHelper(getContext());
}
@Override
@@ -112,23 +113,20 @@ public class DeleteCollectionFragment extends DialogFragment implements LoaderMa
public Exception loadInBackground() {
try {
// delete collection locally
- SQLiteDatabase db = dbHelper.getWritableDatabase();
+ EntityDataStore data = ((App) getContext().getApplicationContext()).getData();
AccountSettings settings = new AccountSettings(getContext(), account);
HttpUrl principal = HttpUrl.get(settings.getUri());
JournalManager journalManager = new JournalManager(HttpClient.create(getContext(), account), principal);
journalManager.deleteJournal(new JournalManager.Journal(settings.password(), collectionInfo.toJson(), collectionInfo.url));
-
- db.delete(ServiceDB.Collections._TABLE, ServiceDB.Collections.ID + "=?", new String[]{String.valueOf(collectionInfo.id)});
+ data.delete(JournalEntity.fetch(data, collectionInfo.url));
return null;
} catch (Exceptions.HttpException e) {
return e;
} catch (InvalidAccountException e) {
return e;
- } finally {
- dbHelper.close();
}
}
}
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/setup/SetupEncryptionFragment.java b/app/src/main/java/com/etesync/syncadapter/ui/setup/SetupEncryptionFragment.java
index 784ef20e..21796b74 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/setup/SetupEncryptionFragment.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/setup/SetupEncryptionFragment.java
@@ -35,10 +35,13 @@ import com.etesync.syncadapter.InvalidAccountException;
import com.etesync.syncadapter.R;
import com.etesync.syncadapter.journalmanager.Helpers;
import com.etesync.syncadapter.model.CollectionInfo;
+import com.etesync.syncadapter.model.JournalEntity;
import com.etesync.syncadapter.model.ServiceDB;
import com.etesync.syncadapter.resource.LocalTaskList;
import com.etesync.syncadapter.ui.setup.BaseConfigurationFinder.Configuration;
import at.bitfire.ical4android.TaskProvider;
+import io.requery.Persistable;
+import io.requery.sql.EntityDataStore;
import lombok.Cleanup;
public class SetupEncryptionFragment extends DialogFragment implements LoaderManager.LoaderCallbacks {
@@ -176,12 +179,13 @@ public class SetupEncryptionFragment extends DialogFragment implements LoaderMan
values.put(ServiceDB.Services.ACCOUNT_NAME, accountName);
values.put(ServiceDB.Services.SERVICE, service);
long serviceID = db.insertWithOnConflict(ServiceDB.Services._TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
+ EntityDataStore data = ((App) getContext().getApplicationContext()).getData();
// insert collections
for (CollectionInfo collection : info.collections.values()) {
- values = collection.toDB();
- values.put(ServiceDB.Collections.SERVICE_ID, serviceID);
- db.insertWithOnConflict(ServiceDB.Collections._TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
+ collection.serviceID = serviceID;
+ JournalEntity journalEntity = new JournalEntity(collection);
+ data.insert(journalEntity);
}
return serviceID;