mirror of
https://github.com/etesync/android
synced 2025-02-02 19:01:06 +00:00
Services: Move to a requery model instead of raw SQL and improve models.
Having it in raw sql was slowing down development, and was error-prone. It's much cleaner now, easier to handle, and enables us to develop faster. In this change I also fixed the fetching of journals to be by service and id, not just id, because just id is not guaranteed to be unique.
This commit is contained in:
parent
8b79529a94
commit
e2f206e02e
@ -13,17 +13,12 @@ import android.accounts.AccountManager;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.DatabaseUtils;
|
import android.database.DatabaseUtils;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import com.etesync.syncadapter.model.JournalEntity;
|
import com.etesync.syncadapter.model.ServiceEntity;
|
||||||
import com.etesync.syncadapter.model.ServiceDB.OpenHelper;
|
|
||||||
import com.etesync.syncadapter.model.ServiceDB.Services;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -105,31 +100,17 @@ public class AccountUpdateService extends Service {
|
|||||||
void cleanupAccounts() {
|
void cleanupAccounts() {
|
||||||
App.log.info("Cleaning up orphaned accounts");
|
App.log.info("Cleaning up orphaned accounts");
|
||||||
|
|
||||||
final OpenHelper dbHelper = new OpenHelper(this);
|
List<String> sqlAccountNames = new LinkedList<>();
|
||||||
try {
|
AccountManager am = AccountManager.get(this);
|
||||||
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
for (Account account : am.getAccountsByType(Constants.ACCOUNT_TYPE))
|
||||||
|
sqlAccountNames.add(account.name);
|
||||||
|
|
||||||
List<String> sqlAccountNames = new LinkedList<>();
|
EntityDataStore<Persistable> data = ((App) getApplication()).getData();
|
||||||
AccountManager am = AccountManager.get(this);
|
|
||||||
for (Account account : am.getAccountsByType(Constants.ACCOUNT_TYPE))
|
|
||||||
sqlAccountNames.add(DatabaseUtils.sqlEscapeString(account.name));
|
|
||||||
|
|
||||||
EntityDataStore<Persistable> data = ((App) getApplication()).getData();
|
if (sqlAccountNames.isEmpty()) {
|
||||||
|
data.delete(ServiceEntity.class).get().value();
|
||||||
if (sqlAccountNames.isEmpty()) {
|
} else {
|
||||||
data.delete(JournalEntity.class).get().value();
|
data.delete(ServiceEntity.class).where(ServiceEntity.ACCOUNT.notIn(sqlAccountNames)).get().value();
|
||||||
db.delete(Services._TABLE, null, null);
|
|
||||||
} else {
|
|
||||||
Cursor cur = db.query(Services._TABLE, new String[]{Services.ID}, Services.ACCOUNT_NAME + " NOT IN (" + TextUtils.join(",", sqlAccountNames) + ")", null, null, null, null);
|
|
||||||
cur.moveToFirst();
|
|
||||||
while(!cur.isAfterLast()) {
|
|
||||||
data.delete(JournalEntity.class).where(JournalEntity.SERVICE.eq(cur.getLong(0))).get().value();
|
|
||||||
cur.moveToNext();
|
|
||||||
}
|
|
||||||
db.delete(Services._TABLE, Services.ACCOUNT_NAME + " NOT IN (" + TextUtils.join(",", sqlAccountNames) + ")", null);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
dbHelper.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,8 +40,10 @@ import com.etesync.syncadapter.log.LogcatHandler;
|
|||||||
import com.etesync.syncadapter.log.PlainTextFormatter;
|
import com.etesync.syncadapter.log.PlainTextFormatter;
|
||||||
import com.etesync.syncadapter.model.CollectionInfo;
|
import com.etesync.syncadapter.model.CollectionInfo;
|
||||||
import com.etesync.syncadapter.model.JournalEntity;
|
import com.etesync.syncadapter.model.JournalEntity;
|
||||||
|
import com.etesync.syncadapter.model.JournalModel;
|
||||||
import com.etesync.syncadapter.model.Models;
|
import com.etesync.syncadapter.model.Models;
|
||||||
import com.etesync.syncadapter.model.ServiceDB;
|
import com.etesync.syncadapter.model.ServiceDB;
|
||||||
|
import com.etesync.syncadapter.model.ServiceEntity;
|
||||||
import com.etesync.syncadapter.model.Settings;
|
import com.etesync.syncadapter.model.Settings;
|
||||||
import com.etesync.syncadapter.resource.LocalAddressBook;
|
import com.etesync.syncadapter.resource.LocalAddressBook;
|
||||||
import com.etesync.syncadapter.resource.LocalCalendar;
|
import com.etesync.syncadapter.resource.LocalCalendar;
|
||||||
@ -227,7 +229,7 @@ public class App extends Application {
|
|||||||
public EntityDataStore<Persistable> getData() {
|
public EntityDataStore<Persistable> getData() {
|
||||||
if (dataStore == null) {
|
if (dataStore == null) {
|
||||||
// override onUpgrade to handle migrating to a new version
|
// override onUpgrade to handle migrating to a new version
|
||||||
DatabaseSource source = new DatabaseSource(this, Models.DEFAULT, 2);
|
DatabaseSource source = new DatabaseSource(this, Models.DEFAULT, 3);
|
||||||
Configuration configuration = source.getConfiguration();
|
Configuration configuration = source.getConfiguration();
|
||||||
dataStore = new EntityDataStore<>(configuration);
|
dataStore = new EntityDataStore<>(configuration);
|
||||||
}
|
}
|
||||||
@ -257,7 +259,7 @@ public class App extends Application {
|
|||||||
|
|
||||||
List<CollectionInfo> collections = readCollections(dbHelper);
|
List<CollectionInfo> collections = readCollections(dbHelper);
|
||||||
for (CollectionInfo info : collections) {
|
for (CollectionInfo info : collections) {
|
||||||
JournalEntity journalEntity = new JournalEntity(info);
|
JournalEntity journalEntity = new JournalEntity(data, info);
|
||||||
data.insert(journalEntity);
|
data.insert(journalEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,6 +293,12 @@ public class App extends Application {
|
|||||||
if (fromVersion < 10) {
|
if (fromVersion < 10) {
|
||||||
HintManager.setHintSeen(this, AccountsActivity.HINT_ACCOUNT_ADD, true);
|
HintManager.setHintSeen(this, AccountsActivity.HINT_ACCOUNT_ADD, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fromVersion < 11) {
|
||||||
|
ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(this);
|
||||||
|
|
||||||
|
migrateServices(dbHelper);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class AppUpdatedReceiver extends BroadcastReceiver {
|
public static class AppUpdatedReceiver extends BroadcastReceiver {
|
||||||
@ -321,4 +329,25 @@ public class App extends Application {
|
|||||||
}
|
}
|
||||||
return collections;
|
return collections;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void migrateServices(ServiceDB.OpenHelper dbHelper) {
|
||||||
|
@Cleanup SQLiteDatabase db = dbHelper.getReadableDatabase();
|
||||||
|
EntityDataStore<Persistable> data = this.getData();
|
||||||
|
@Cleanup Cursor cursor = db.query(ServiceDB.Services._TABLE, null, null, null, null, null, null);
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
DatabaseUtils.cursorRowToContentValues(cursor, values);
|
||||||
|
ServiceEntity service = new ServiceEntity();
|
||||||
|
service.setAccount(values.getAsString(ServiceDB.Services.ACCOUNT_NAME));
|
||||||
|
service.setType(CollectionInfo.Type.valueOf(values.getAsString(ServiceDB.Services.SERVICE)));
|
||||||
|
data.insert(service);
|
||||||
|
|
||||||
|
for (JournalEntity journalEntity : data.select(JournalEntity.class).where(JournalEntity.SERVICE.eq(values.getAsLong(ServiceDB.Services.ID))).get()) {
|
||||||
|
journalEntity.setServiceModel(service);
|
||||||
|
data.update(journalEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
db.delete(ServiceDB.Services._TABLE, null, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,22 +8,13 @@
|
|||||||
|
|
||||||
package com.etesync.syncadapter;
|
package com.etesync.syncadapter;
|
||||||
|
|
||||||
import android.accounts.Account;
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import com.etesync.syncadapter.model.ServiceDB;
|
|
||||||
import com.etesync.syncadapter.model.ServiceDB.Services;
|
|
||||||
import com.etesync.syncadapter.resource.LocalTaskList;
|
import com.etesync.syncadapter.resource.LocalTaskList;
|
||||||
import at.bitfire.ical4android.TaskProvider;
|
|
||||||
import lombok.Cleanup;
|
|
||||||
|
|
||||||
public class PackageChangedReceiver extends BroadcastReceiver {
|
public class PackageChangedReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
@ -40,24 +31,7 @@ public class PackageChangedReceiver extends BroadcastReceiver {
|
|||||||
App.log.info("Package (un)installed; OpenTasks provider now available = " + tasksInstalled);
|
App.log.info("Package (un)installed; OpenTasks provider now available = " + tasksInstalled);
|
||||||
|
|
||||||
// check all accounts and (de)activate OpenTasks if a CalDAV service is defined
|
// check all accounts and (de)activate OpenTasks if a CalDAV service is defined
|
||||||
@Cleanup ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(context);
|
// FIXME: Do something if we ever bring back tasks.
|
||||||
SQLiteDatabase db = dbHelper.getReadableDatabase();
|
|
||||||
|
|
||||||
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[] { Services.ACCOUNT_NAME },
|
|
||||||
Services.SERVICE + "=?", new String[] { Services.SERVICE_CALDAV }, null, null, null);
|
|
||||||
while (cursor.moveToNext()) {
|
|
||||||
Account account = new Account(cursor.getString(0), Constants.ACCOUNT_TYPE);
|
|
||||||
|
|
||||||
if (tasksInstalled) {
|
|
||||||
if (ContentResolver.getIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority) <= 0) {
|
|
||||||
ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 1);
|
|
||||||
ContentResolver.setSyncAutomatically(account, TaskProvider.ProviderName.OpenTasks.authority, true);
|
|
||||||
ContentResolver.addPeriodicSync(account, TaskProvider.ProviderName.OpenTasks.authority, new Bundle(), Constants.DEFAULT_SYNC_INTERVAL);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 0);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@ import com.google.gson.annotations.Expose;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import io.requery.Persistable;
|
||||||
|
import io.requery.sql.EntityDataStore;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
@ToString(exclude = {"id"})
|
@ToString(exclude = {"id"})
|
||||||
@ -25,7 +27,7 @@ public class CollectionInfo implements Serializable {
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public long id;
|
public long id;
|
||||||
|
|
||||||
public Long serviceID;
|
public int serviceID;
|
||||||
|
|
||||||
public enum Type {
|
public enum Type {
|
||||||
ADDRESS_BOOK,
|
ADDRESS_BOOK,
|
||||||
@ -80,7 +82,7 @@ public class CollectionInfo implements Serializable {
|
|||||||
public static CollectionInfo fromDB(ContentValues values) {
|
public static CollectionInfo fromDB(ContentValues values) {
|
||||||
CollectionInfo info = new CollectionInfo();
|
CollectionInfo info = new CollectionInfo();
|
||||||
info.id = values.getAsLong(Collections.ID);
|
info.id = values.getAsLong(Collections.ID);
|
||||||
info.serviceID = values.getAsLong(Collections.SERVICE_ID);
|
info.serviceID = values.getAsInteger(Collections.SERVICE_ID);
|
||||||
|
|
||||||
info.uid = values.getAsString(Collections.URL);
|
info.uid = values.getAsString(Collections.URL);
|
||||||
info.readOnly = values.getAsInteger(Collections.READ_ONLY) != 0;
|
info.readOnly = values.getAsInteger(Collections.READ_ONLY) != 0;
|
||||||
@ -95,6 +97,10 @@ public class CollectionInfo implements Serializable {
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ServiceEntity getServiceEntity(EntityDataStore<Persistable> data) {
|
||||||
|
return data.findByKey(ServiceEntity.class, serviceID);
|
||||||
|
}
|
||||||
|
|
||||||
public static CollectionInfo fromJson(String json) {
|
public static CollectionInfo fromJson(String json) {
|
||||||
return new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create().fromJson(json, CollectionInfo.class);
|
return new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create().fromJson(json, CollectionInfo.class);
|
||||||
}
|
}
|
||||||
|
@ -37,14 +37,19 @@ public class JournalModel {
|
|||||||
|
|
||||||
byte[] encryptedKey;
|
byte[] encryptedKey;
|
||||||
|
|
||||||
@Index(value = "uid_unique")
|
|
||||||
|
@Deprecated
|
||||||
long service;
|
long service;
|
||||||
|
|
||||||
|
@ForeignKey(update = ReferentialAction.CASCADE)
|
||||||
|
@ManyToOne
|
||||||
|
Service serviceModel;
|
||||||
|
|
||||||
boolean deleted;
|
boolean deleted;
|
||||||
|
|
||||||
@PostLoad
|
@PostLoad
|
||||||
void afterLoad() {
|
void afterLoad() {
|
||||||
this.info.serviceID = service;
|
this.info.serviceID = this.serviceModel.id;
|
||||||
this.info.uid = uid;
|
this.info.uid = uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,21 +57,21 @@ public class JournalModel {
|
|||||||
this.deleted = false;
|
this.deleted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Journal(CollectionInfo info) {
|
public Journal(EntityDataStore<Persistable> data, CollectionInfo info) {
|
||||||
this();
|
this();
|
||||||
this.info = info;
|
this.info = info;
|
||||||
this.uid = info.uid;
|
this.uid = info.uid;
|
||||||
this.service = info.serviceID;
|
this.serviceModel = info.getServiceEntity(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<JournalEntity> getJournals(EntityDataStore<Persistable> data, long service) {
|
public static List<JournalEntity> getJournals(EntityDataStore<Persistable> data, ServiceEntity serviceEntity) {
|
||||||
return data.select(JournalEntity.class).where(JournalEntity.SERVICE.eq(service).and(JournalEntity.DELETED.eq(false))).get().toList();
|
return data.select(JournalEntity.class).where(JournalEntity.SERVICE_MODEL.eq(serviceEntity).and(JournalEntity.DELETED.eq(false))).get().toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<CollectionInfo> getCollections(EntityDataStore<Persistable> data, long service) {
|
public static List<CollectionInfo> getCollections(EntityDataStore<Persistable> data, ServiceEntity serviceEntity) {
|
||||||
List<CollectionInfo> ret = new LinkedList<>();
|
List<CollectionInfo> ret = new LinkedList<>();
|
||||||
|
|
||||||
List<JournalEntity> journals = getJournals(data, service);
|
List<JournalEntity> journals = getJournals(data, serviceEntity);
|
||||||
for (JournalEntity journal : journals) {
|
for (JournalEntity journal : journals) {
|
||||||
// FIXME: For some reason this isn't always being called, manually do it here.
|
// FIXME: For some reason this isn't always being called, manually do it here.
|
||||||
journal.afterLoad();
|
journal.afterLoad();
|
||||||
@ -76,8 +81,8 @@ public class JournalModel {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JournalEntity fetch(EntityDataStore<Persistable> data, String url) {
|
public static JournalEntity fetch(EntityDataStore<Persistable> data, ServiceEntity serviceEntity, String uid) {
|
||||||
JournalEntity ret = data.select(JournalEntity.class).where(JournalEntity.UID.eq(url)).limit(1).get().firstOrNull();
|
JournalEntity ret = data.select(JournalEntity.class).where(JournalEntity.SERVICE_MODEL.eq(serviceEntity).and(JournalEntity.UID.eq(uid))).limit(1).get().firstOrNull();
|
||||||
if (ret != null) {
|
if (ret != null) {
|
||||||
// FIXME: For some reason this isn't always being called, manually do it here.
|
// FIXME: For some reason this isn't always being called, manually do it here.
|
||||||
ret.afterLoad();
|
ret.afterLoad();
|
||||||
@ -86,9 +91,9 @@ public class JournalModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static JournalEntity fetchOrCreate(EntityDataStore<Persistable> data, CollectionInfo collection) {
|
public static JournalEntity fetchOrCreate(EntityDataStore<Persistable> data, CollectionInfo collection) {
|
||||||
JournalEntity journalEntity = fetch(data, collection.uid);
|
JournalEntity journalEntity = fetch(data, collection.getServiceEntity(data), collection.uid);
|
||||||
if (journalEntity == null) {
|
if (journalEntity == null) {
|
||||||
journalEntity = new JournalEntity(collection);
|
journalEntity = new JournalEntity(data, collection);
|
||||||
} else {
|
} else {
|
||||||
journalEntity.setInfo(collection);
|
journalEntity.setInfo(collection);
|
||||||
}
|
}
|
||||||
@ -125,6 +130,26 @@ public class JournalModel {
|
|||||||
Journal journal;
|
Journal journal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "Service", uniqueIndexes = "service_unique_together")
|
||||||
|
public static abstract class Service {
|
||||||
|
@Key
|
||||||
|
@Generated
|
||||||
|
int id;
|
||||||
|
|
||||||
|
@Index(value = "service_unique_together")
|
||||||
|
@Column(nullable = false)
|
||||||
|
String account;
|
||||||
|
|
||||||
|
@Index(value = "service_unique_together")
|
||||||
|
CollectionInfo.Type type;
|
||||||
|
|
||||||
|
public static ServiceEntity fetch(EntityDataStore<Persistable> data, String account, CollectionInfo.Type type) {
|
||||||
|
return data.select(ServiceEntity.class).where(ServiceEntity.ACCOUNT.eq(account).and(ServiceEntity.TYPE.eq(type))).limit(1).get().firstOrNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static class CollectionInfoConverter implements Converter<CollectionInfo, String> {
|
static class CollectionInfoConverter implements Converter<CollectionInfo, String> {
|
||||||
@Override
|
@Override
|
||||||
public Class<CollectionInfo> getMappedType() {
|
public Class<CollectionInfo> getMappedType() {
|
||||||
|
@ -33,17 +33,13 @@ public class ServiceDB {
|
|||||||
VALUE = "value";
|
VALUE = "value";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static class Services {
|
public static class Services {
|
||||||
public static final String
|
public static final String
|
||||||
_TABLE = "services",
|
_TABLE = "services",
|
||||||
ID = "_id",
|
ID = "_id",
|
||||||
ACCOUNT_NAME = "accountName",
|
ACCOUNT_NAME = "accountName",
|
||||||
SERVICE = "service";
|
SERVICE = "service";
|
||||||
|
|
||||||
// allowed values for SERVICE column
|
|
||||||
public static final String
|
|
||||||
SERVICE_CALDAV = CollectionInfo.Type.CALENDAR.toString(),
|
|
||||||
SERVICE_CARDDAV = CollectionInfo.Type.ADDRESS_BOOK.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@ -90,15 +86,8 @@ public class ServiceDB {
|
|||||||
db.execSQL("CREATE TABLE " + Settings._TABLE + "(" +
|
db.execSQL("CREATE TABLE " + Settings._TABLE + "(" +
|
||||||
Settings.NAME + " TEXT NOT NULL," +
|
Settings.NAME + " TEXT NOT NULL," +
|
||||||
Settings.VALUE + " TEXT NOT NULL" +
|
Settings.VALUE + " TEXT NOT NULL" +
|
||||||
")");
|
")");
|
||||||
db.execSQL("CREATE UNIQUE INDEX settings_name ON " + Settings._TABLE + " (" + Settings.NAME + ")");
|
db.execSQL("CREATE UNIQUE INDEX settings_name ON " + Settings._TABLE + " (" + Settings.NAME + ")");
|
||||||
|
|
||||||
db.execSQL("CREATE TABLE " + Services._TABLE + "(" +
|
|
||||||
Services.ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
|
|
||||||
Services.ACCOUNT_NAME + " TEXT NOT NULL," +
|
|
||||||
Services.SERVICE + " TEXT NOT NULL" +
|
|
||||||
")");
|
|
||||||
db.execSQL("CREATE UNIQUE INDEX services_account ON " + Services._TABLE + " (" + Services.ACCOUNT_NAME + "," + Services.SERVICE + ")");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -112,7 +101,7 @@ public class ServiceDB {
|
|||||||
db.beginTransactionNonExclusive();
|
db.beginTransactionNonExclusive();
|
||||||
|
|
||||||
// iterate through all tables
|
// iterate through all tables
|
||||||
@Cleanup Cursor cursorTables = db.query("sqlite_master", new String[] { "name" }, "type='table'", null, null, null, null);
|
@Cleanup Cursor cursorTables = db.query("sqlite_master", new String[]{"name"}, "type='table'", null, null, null, null);
|
||||||
while (cursorTables.moveToNext()) {
|
while (cursorTables.moveToNext()) {
|
||||||
String table = cursorTables.getString(0);
|
String table = cursorTables.getString(0);
|
||||||
sb.append(table).append("\n");
|
sb.append(table).append("\n");
|
||||||
@ -153,47 +142,5 @@ public class ServiceDB {
|
|||||||
}
|
}
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public Account getServiceAccount(SQLiteDatabase db, long service) {
|
|
||||||
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[]{Services.ACCOUNT_NAME}, Services.ID + "=?", new String[]{String.valueOf(service)}, null, null, null);
|
|
||||||
if (cursor.moveToNext()) {
|
|
||||||
return new Account(cursor.getString(0), Constants.ACCOUNT_TYPE);
|
|
||||||
} else
|
|
||||||
throw new IllegalArgumentException("Service not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public String getServiceType(SQLiteDatabase db, long service) {
|
|
||||||
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[]{Services.SERVICE}, Services.ID + "=?", new String[]{String.valueOf(service)}, null, null, null);
|
|
||||||
if (cursor.moveToNext())
|
|
||||||
return cursor.getString(0);
|
|
||||||
else
|
|
||||||
throw new IllegalArgumentException("Service not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public Long getService(@NonNull SQLiteDatabase db, @NonNull Account account, String service) {
|
|
||||||
@Cleanup Cursor c = db.query(Services._TABLE, new String[]{Services.ID},
|
|
||||||
Services.ACCOUNT_NAME + "=? AND " + Services.SERVICE + "=?", new String[]{account.name, service}, null, null, null);
|
|
||||||
if (c.moveToNext())
|
|
||||||
return c.getLong(0);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public Long getService(@NonNull Account account, String service) {
|
|
||||||
@Cleanup SQLiteDatabase db = getReadableDatabase();
|
|
||||||
return getService(db, account, service);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void onRenameAccount(@NonNull SQLiteDatabase db, @NonNull String oldName, @NonNull String newName) {
|
|
||||||
ContentValues values = new ContentValues(1);
|
|
||||||
values.put(Services.ACCOUNT_NAME, newName);
|
|
||||||
db.update(Services._TABLE, values, Services.ACCOUNT_NAME + "=?", new String[] { oldName });
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@ import android.content.ContentResolver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SyncResult;
|
import android.content.SyncResult;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.database.sqlite.SQLiteException;
|
import android.database.sqlite.SQLiteException;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.CalendarContract;
|
import android.provider.CalendarContract;
|
||||||
@ -27,8 +26,8 @@ import com.etesync.syncadapter.R;
|
|||||||
import com.etesync.syncadapter.journalmanager.Exceptions;
|
import com.etesync.syncadapter.journalmanager.Exceptions;
|
||||||
import com.etesync.syncadapter.model.CollectionInfo;
|
import com.etesync.syncadapter.model.CollectionInfo;
|
||||||
import com.etesync.syncadapter.model.JournalEntity;
|
import com.etesync.syncadapter.model.JournalEntity;
|
||||||
import com.etesync.syncadapter.model.ServiceDB;
|
import com.etesync.syncadapter.model.JournalModel;
|
||||||
import com.etesync.syncadapter.model.ServiceDB.Services;
|
import com.etesync.syncadapter.model.ServiceEntity;
|
||||||
import com.etesync.syncadapter.resource.LocalCalendar;
|
import com.etesync.syncadapter.resource.LocalCalendar;
|
||||||
import com.etesync.syncadapter.ui.DebugInfoActivity;
|
import com.etesync.syncadapter.ui.DebugInfoActivity;
|
||||||
|
|
||||||
@ -109,47 +108,40 @@ public class CalendarsSyncAdapterService extends SyncAdapterService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateLocalCalendars(ContentProviderClient provider, Account account, AccountSettings settings) throws CalendarStorageException {
|
private void updateLocalCalendars(ContentProviderClient provider, Account account, AccountSettings settings) throws CalendarStorageException {
|
||||||
ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(getContext());
|
EntityDataStore<Persistable> data = ((App) getContext().getApplicationContext()).getData();
|
||||||
try {
|
ServiceEntity service = JournalModel.Service.fetch(data, account.name, CollectionInfo.Type.CALENDAR);
|
||||||
// enumerate remote and local calendars
|
|
||||||
SQLiteDatabase db = dbHelper.getReadableDatabase();
|
|
||||||
Long service = dbHelper.getService(db, account, Services.SERVICE_CALDAV);
|
|
||||||
|
|
||||||
EntityDataStore<Persistable> data = ((App) getContext().getApplicationContext()).getData();
|
Map<String, CollectionInfo> remote = new HashMap<>();
|
||||||
Map<String, CollectionInfo> remote = new HashMap<>();
|
List<CollectionInfo> remoteCollections = JournalEntity.getCollections(data, service);
|
||||||
List<CollectionInfo> remoteCollections = JournalEntity.getCollections(data, service);
|
for (CollectionInfo info : remoteCollections) {
|
||||||
for (CollectionInfo info : remoteCollections) {
|
remote.put(info.uid, info);
|
||||||
remote.put(info.uid, info);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
LocalCalendar[] local = (LocalCalendar[])LocalCalendar.find(account, provider, LocalCalendar.Factory.INSTANCE, null, null);
|
LocalCalendar[] local = (LocalCalendar[]) LocalCalendar.find(account, provider, LocalCalendar.Factory.INSTANCE, null, null);
|
||||||
|
|
||||||
boolean updateColors = settings.getManageCalendarColors();
|
boolean updateColors = settings.getManageCalendarColors();
|
||||||
|
|
||||||
// delete obsolete local calendar
|
// delete obsolete local calendar
|
||||||
for (LocalCalendar calendar : local) {
|
for (LocalCalendar calendar : local) {
|
||||||
String url = calendar.getName();
|
String url = calendar.getName();
|
||||||
if (!remote.containsKey(url)) {
|
if (!remote.containsKey(url)) {
|
||||||
App.log.fine("Deleting obsolete local calendar " + url);
|
App.log.fine("Deleting obsolete local calendar " + url);
|
||||||
calendar.delete();
|
calendar.delete();
|
||||||
} else {
|
} else {
|
||||||
// remote CollectionInfo found for this local collection, update data
|
// remote CollectionInfo found for this local collection, update data
|
||||||
CollectionInfo info = remote.get(url);
|
|
||||||
App.log.fine("Updating local calendar " + url + " with " + info);
|
|
||||||
calendar.update(info, updateColors);
|
|
||||||
// we already have a local calendar for this remote collection, don't take into consideration anymore
|
|
||||||
remote.remove(url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create new local calendars
|
|
||||||
for (String url : remote.keySet()) {
|
|
||||||
CollectionInfo info = remote.get(url);
|
CollectionInfo info = remote.get(url);
|
||||||
App.log.info("Adding local calendar list " + info);
|
App.log.fine("Updating local calendar " + url + " with " + info);
|
||||||
LocalCalendar.create(account, provider, info);
|
calendar.update(info, updateColors);
|
||||||
|
// we already have a local calendar for this remote collection, don't take into consideration anymore
|
||||||
|
remote.remove(url);
|
||||||
}
|
}
|
||||||
} finally {
|
}
|
||||||
dbHelper.close();
|
|
||||||
|
// create new local calendars
|
||||||
|
for (String url : remote.keySet()) {
|
||||||
|
CollectionInfo info = remote.get(url);
|
||||||
|
App.log.info("Adding local calendar list " + info);
|
||||||
|
LocalCalendar.create(account, provider, info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@ import android.content.ContentResolver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SyncResult;
|
import android.content.SyncResult;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import com.etesync.syncadapter.AccountSettings;
|
import com.etesync.syncadapter.AccountSettings;
|
||||||
@ -26,7 +25,9 @@ import com.etesync.syncadapter.R;
|
|||||||
import com.etesync.syncadapter.journalmanager.Exceptions;
|
import com.etesync.syncadapter.journalmanager.Exceptions;
|
||||||
import com.etesync.syncadapter.model.CollectionInfo;
|
import com.etesync.syncadapter.model.CollectionInfo;
|
||||||
import com.etesync.syncadapter.model.JournalEntity;
|
import com.etesync.syncadapter.model.JournalEntity;
|
||||||
|
import com.etesync.syncadapter.model.JournalModel;
|
||||||
import com.etesync.syncadapter.model.ServiceDB;
|
import com.etesync.syncadapter.model.ServiceDB;
|
||||||
|
import com.etesync.syncadapter.model.ServiceEntity;
|
||||||
import com.etesync.syncadapter.ui.DebugInfoActivity;
|
import com.etesync.syncadapter.ui.DebugInfoActivity;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@ -65,11 +66,12 @@ public class ContactsSyncAdapterService extends SyncAdapterService {
|
|||||||
|
|
||||||
new RefreshCollections(account, CollectionInfo.Type.ADDRESS_BOOK).run();
|
new RefreshCollections(account, CollectionInfo.Type.ADDRESS_BOOK).run();
|
||||||
|
|
||||||
SQLiteDatabase db = dbHelper.getReadableDatabase();
|
EntityDataStore<Persistable> data = ((App) getContext().getApplicationContext()).getData();
|
||||||
Long service = dbHelper.getService(db, account, ServiceDB.Services.SERVICE_CARDDAV);
|
|
||||||
|
ServiceEntity service = JournalModel.Service.fetch(data, account.name, CollectionInfo.Type.ADDRESS_BOOK);
|
||||||
|
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
HttpUrl principal = HttpUrl.get(settings.getUri());
|
HttpUrl principal = HttpUrl.get(settings.getUri());
|
||||||
EntityDataStore<Persistable> data = ((App) getContext().getApplicationContext()).getData();
|
|
||||||
CollectionInfo info = JournalEntity.getCollections(data, service).get(0);
|
CollectionInfo info = JournalEntity.getCollections(data, service).get(0);
|
||||||
try {
|
try {
|
||||||
ContactsSyncManager syncManager = new ContactsSyncManager(getContext(), account, settings, extras, authority, provider, syncResult, principal, info);
|
ContactsSyncManager syncManager = new ContactsSyncManager(getContext(), account, settings, extras, authority, provider, syncResult, principal, info);
|
||||||
|
@ -47,7 +47,9 @@ import com.etesync.syncadapter.journalmanager.Exceptions;
|
|||||||
import com.etesync.syncadapter.journalmanager.JournalManager;
|
import com.etesync.syncadapter.journalmanager.JournalManager;
|
||||||
import com.etesync.syncadapter.model.CollectionInfo;
|
import com.etesync.syncadapter.model.CollectionInfo;
|
||||||
import com.etesync.syncadapter.model.JournalEntity;
|
import com.etesync.syncadapter.model.JournalEntity;
|
||||||
|
import com.etesync.syncadapter.model.JournalModel;
|
||||||
import com.etesync.syncadapter.model.ServiceDB;
|
import com.etesync.syncadapter.model.ServiceDB;
|
||||||
|
import com.etesync.syncadapter.model.ServiceEntity;
|
||||||
import com.etesync.syncadapter.ui.PermissionsActivity;
|
import com.etesync.syncadapter.ui.PermissionsActivity;
|
||||||
|
|
||||||
import io.requery.Persistable;
|
import io.requery.Persistable;
|
||||||
@ -175,22 +177,16 @@ public abstract class SyncAdapterService extends Service {
|
|||||||
journals.add(new Pair<>(journal, info));
|
journals.add(new Pair<>(journal, info));
|
||||||
}
|
}
|
||||||
|
|
||||||
db.beginTransactionNonExclusive();
|
saveCollections(journals);
|
||||||
try {
|
|
||||||
saveCollections(db, journals);
|
|
||||||
db.setTransactionSuccessful();
|
|
||||||
} finally {
|
|
||||||
db.endTransaction();
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
dbHelper.close();
|
dbHelper.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveCollections(SQLiteDatabase db, Iterable<Pair<JournalManager.Journal, CollectionInfo>> journals) {
|
private void saveCollections(Iterable<Pair<JournalManager.Journal, CollectionInfo>> journals) {
|
||||||
Long service = dbHelper.getService(db, account, serviceType.toString());
|
|
||||||
|
|
||||||
EntityDataStore<Persistable> data = ((App) context.getApplicationContext()).getData();
|
EntityDataStore<Persistable> data = ((App) context.getApplicationContext()).getData();
|
||||||
|
ServiceEntity service = JournalModel.Service.fetch(data, account.name, serviceType);
|
||||||
|
|
||||||
Map<String, JournalEntity> existing = new HashMap<>();
|
Map<String, JournalEntity> existing = new HashMap<>();
|
||||||
for (JournalEntity journalEntity : JournalEntity.getJournals(data, service)) {
|
for (JournalEntity journalEntity : JournalEntity.getJournals(data, service)) {
|
||||||
existing.put(journalEntity.getUid(), journalEntity);
|
existing.put(journalEntity.getUid(), journalEntity);
|
||||||
@ -201,7 +197,7 @@ public abstract class SyncAdapterService extends Service {
|
|||||||
CollectionInfo collection = pair.second;
|
CollectionInfo collection = pair.second;
|
||||||
App.log.log(Level.FINE, "Saving collection", journal.getUid());
|
App.log.log(Level.FINE, "Saving collection", journal.getUid());
|
||||||
|
|
||||||
collection.serviceID = service;
|
collection.serviceID = service.getId();
|
||||||
JournalEntity journalEntity = JournalEntity.fetchOrCreate(data, collection);
|
JournalEntity journalEntity = JournalEntity.fetchOrCreate(data, collection);
|
||||||
journalEntity.setOwner(journal.getOwner());
|
journalEntity.setOwner(journal.getOwner());
|
||||||
journalEntity.setEncryptedKey(journal.getKey());
|
journalEntity.setEncryptedKey(journal.getKey());
|
||||||
|
@ -27,6 +27,8 @@ import com.etesync.syncadapter.journalmanager.JournalEntryManager;
|
|||||||
import com.etesync.syncadapter.model.CollectionInfo;
|
import com.etesync.syncadapter.model.CollectionInfo;
|
||||||
import com.etesync.syncadapter.model.EntryEntity;
|
import com.etesync.syncadapter.model.EntryEntity;
|
||||||
import com.etesync.syncadapter.model.JournalEntity;
|
import com.etesync.syncadapter.model.JournalEntity;
|
||||||
|
import com.etesync.syncadapter.model.JournalModel;
|
||||||
|
import com.etesync.syncadapter.model.ServiceEntity;
|
||||||
import com.etesync.syncadapter.model.SyncEntry;
|
import com.etesync.syncadapter.model.SyncEntry;
|
||||||
import com.etesync.syncadapter.resource.LocalCollection;
|
import com.etesync.syncadapter.resource.LocalCollection;
|
||||||
import com.etesync.syncadapter.resource.LocalResource;
|
import com.etesync.syncadapter.resource.LocalResource;
|
||||||
@ -108,7 +110,8 @@ abstract public class SyncManager {
|
|||||||
httpClient = HttpClient.create(context, account);
|
httpClient = HttpClient.create(context, account);
|
||||||
|
|
||||||
data = ((App) context.getApplicationContext()).getData();
|
data = ((App) context.getApplicationContext()).getData();
|
||||||
info = JournalEntity.fetch(data, journalUid).getInfo();
|
ServiceEntity serviceEntity = JournalModel.Service.fetch(data, account.name, serviceType);
|
||||||
|
info = JournalEntity.fetch(data, serviceEntity, journalUid).getInfo();
|
||||||
|
|
||||||
// dismiss previous error notifications
|
// dismiss previous error notifications
|
||||||
notificationManager = new NotificationHelper(context, journalUid, notificationId());
|
notificationManager = new NotificationHelper(context, journalUid, notificationId());
|
||||||
@ -232,7 +235,7 @@ abstract public class SyncManager {
|
|||||||
|
|
||||||
private JournalEntity getJournalEntity() {
|
private JournalEntity getJournalEntity() {
|
||||||
if (_journalEntity == null)
|
if (_journalEntity == null)
|
||||||
_journalEntity = data.select(JournalEntity.class).where(JournalEntity.UID.eq(journal.getUid())).limit(1).get().first();
|
_journalEntity = JournalModel.Journal.fetch(data, info.getServiceEntity(data), journal.getUid());
|
||||||
return _journalEntity;
|
return _journalEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +24,6 @@ import android.content.Intent;
|
|||||||
import android.content.Loader;
|
import android.content.Loader;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.content.SyncStatusObserver;
|
import android.content.SyncStatusObserver;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@ -57,8 +55,7 @@ import com.etesync.syncadapter.Constants;
|
|||||||
import com.etesync.syncadapter.R;
|
import com.etesync.syncadapter.R;
|
||||||
import com.etesync.syncadapter.model.CollectionInfo;
|
import com.etesync.syncadapter.model.CollectionInfo;
|
||||||
import com.etesync.syncadapter.model.JournalEntity;
|
import com.etesync.syncadapter.model.JournalEntity;
|
||||||
import com.etesync.syncadapter.model.ServiceDB.OpenHelper;
|
import com.etesync.syncadapter.model.ServiceEntity;
|
||||||
import com.etesync.syncadapter.model.ServiceDB.Services;
|
|
||||||
import com.etesync.syncadapter.resource.LocalCalendar;
|
import com.etesync.syncadapter.resource.LocalCalendar;
|
||||||
import com.etesync.syncadapter.utils.HintManager;
|
import com.etesync.syncadapter.utils.HintManager;
|
||||||
import com.etesync.syncadapter.utils.ShowcaseBuilder;
|
import com.etesync.syncadapter.utils.ShowcaseBuilder;
|
||||||
@ -71,7 +68,6 @@ import at.bitfire.cert4android.CustomCertManager;
|
|||||||
import at.bitfire.ical4android.TaskProvider;
|
import at.bitfire.ical4android.TaskProvider;
|
||||||
import io.requery.Persistable;
|
import io.requery.Persistable;
|
||||||
import io.requery.sql.EntityDataStore;
|
import io.requery.sql.EntityDataStore;
|
||||||
import lombok.Cleanup;
|
|
||||||
import tourguide.tourguide.ToolTip;
|
import tourguide.tourguide.ToolTip;
|
||||||
|
|
||||||
import static android.content.ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;
|
import static android.content.ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;
|
||||||
@ -318,31 +314,23 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
public AccountInfo loadInBackground() {
|
public AccountInfo loadInBackground() {
|
||||||
AccountInfo info = new AccountInfo();
|
AccountInfo info = new AccountInfo();
|
||||||
|
|
||||||
@Cleanup OpenHelper dbHelper = new OpenHelper(getContext());
|
|
||||||
SQLiteDatabase db = dbHelper.getReadableDatabase();
|
|
||||||
EntityDataStore<Persistable> data = ((App) getContext().getApplicationContext()).getData();
|
EntityDataStore<Persistable> data = ((App) getContext().getApplicationContext()).getData();
|
||||||
|
|
||||||
@Cleanup Cursor cursor = db.query(
|
for (ServiceEntity serviceEntity : data.select(ServiceEntity.class).where(ServiceEntity.ACCOUNT.eq(account.name)).get()) {
|
||||||
Services._TABLE,
|
long id = serviceEntity.getId();
|
||||||
new String[] { Services.ID, Services.SERVICE },
|
CollectionInfo.Type service = serviceEntity.getType();
|
||||||
Services.ACCOUNT_NAME + "=?", new String[] { account.name },
|
if (service.equals(CollectionInfo.Type.ADDRESS_BOOK)) {
|
||||||
null, null, null);
|
|
||||||
|
|
||||||
while (cursor.moveToNext()) {
|
|
||||||
long id = cursor.getLong(0);
|
|
||||||
String service = cursor.getString(1);
|
|
||||||
if (Services.SERVICE_CARDDAV.equals(service)) {
|
|
||||||
info.carddav = new AccountInfo.ServiceInfo();
|
info.carddav = new AccountInfo.ServiceInfo();
|
||||||
info.carddav.id = id;
|
info.carddav.id = id;
|
||||||
info.carddav.refreshing = (davService != null && davService.isRefreshing(id)) || ContentResolver.isSyncActive(account, ContactsContract.AUTHORITY);
|
info.carddav.refreshing = (davService != null && davService.isRefreshing(id)) || ContentResolver.isSyncActive(account, ContactsContract.AUTHORITY);
|
||||||
info.carddav.collections = JournalEntity.getCollections(data, id);
|
info.carddav.collections = JournalEntity.getCollections(data, serviceEntity);
|
||||||
} else if (Services.SERVICE_CALDAV.equals(service)) {
|
} else if (service.equals(CollectionInfo.Type.CALENDAR)) {
|
||||||
info.caldav = new AccountInfo.ServiceInfo();
|
info.caldav = new AccountInfo.ServiceInfo();
|
||||||
info.caldav.id = id;
|
info.caldav.id = id;
|
||||||
info.caldav.refreshing = (davService != null && davService.isRefreshing(id)) ||
|
info.caldav.refreshing = (davService != null && davService.isRefreshing(id)) ||
|
||||||
ContentResolver.isSyncActive(account, CalendarContract.AUTHORITY) ||
|
ContentResolver.isSyncActive(account, CalendarContract.AUTHORITY) ||
|
||||||
ContentResolver.isSyncActive(account, TaskProvider.ProviderName.OpenTasks.authority);
|
ContentResolver.isSyncActive(account, TaskProvider.ProviderName.OpenTasks.authority);
|
||||||
info.caldav.collections = JournalEntity.getCollections(data, id);
|
info.caldav.collections = JournalEntity.getCollections(data, serviceEntity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return info;
|
return info;
|
||||||
|
@ -35,7 +35,9 @@ import com.etesync.syncadapter.journalmanager.Exceptions;
|
|||||||
import com.etesync.syncadapter.journalmanager.JournalManager;
|
import com.etesync.syncadapter.journalmanager.JournalManager;
|
||||||
import com.etesync.syncadapter.model.CollectionInfo;
|
import com.etesync.syncadapter.model.CollectionInfo;
|
||||||
import com.etesync.syncadapter.model.JournalEntity;
|
import com.etesync.syncadapter.model.JournalEntity;
|
||||||
|
import com.etesync.syncadapter.model.JournalModel;
|
||||||
import com.etesync.syncadapter.model.ServiceDB;
|
import com.etesync.syncadapter.model.ServiceDB;
|
||||||
|
import com.etesync.syncadapter.model.ServiceEntity;
|
||||||
|
|
||||||
import io.requery.Persistable;
|
import io.requery.Persistable;
|
||||||
import io.requery.sql.EntityDataStore;
|
import io.requery.sql.EntityDataStore;
|
||||||
@ -125,31 +127,21 @@ public class CreateCollectionFragment extends DialogFragment implements LoaderMa
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Exception loadInBackground() {
|
public Exception loadInBackground() {
|
||||||
ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(getContext());
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String authority = null;
|
String authority = null;
|
||||||
// now insert collection into database:
|
|
||||||
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
EntityDataStore<Persistable> data = ((App) getContext().getApplicationContext()).getData();
|
||||||
|
|
||||||
// 1. find service ID
|
// 1. find service ID
|
||||||
String serviceType;
|
|
||||||
if (info.type == CollectionInfo.Type.ADDRESS_BOOK) {
|
if (info.type == CollectionInfo.Type.ADDRESS_BOOK) {
|
||||||
serviceType = ServiceDB.Services.SERVICE_CARDDAV;
|
|
||||||
authority = ContactsContract.AUTHORITY;
|
authority = ContactsContract.AUTHORITY;
|
||||||
} else if (info.type == CollectionInfo.Type.CALENDAR) {
|
} else if (info.type == CollectionInfo.Type.CALENDAR) {
|
||||||
serviceType = ServiceDB.Services.SERVICE_CALDAV;
|
|
||||||
authority = CalendarContract.AUTHORITY;
|
authority = CalendarContract.AUTHORITY;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Collection must be an address book or calendar");
|
throw new IllegalArgumentException("Collection must be an address book or calendar");
|
||||||
}
|
}
|
||||||
@Cleanup Cursor c = db.query(ServiceDB.Services._TABLE, new String[]{ServiceDB.Services.ID},
|
|
||||||
ServiceDB.Services.ACCOUNT_NAME + "=? AND " + ServiceDB.Services.SERVICE + "=?",
|
ServiceEntity serviceEntity = JournalModel.Service.fetch(data, account.name, info.type);
|
||||||
new String[]{account.name, serviceType}, null, null, null
|
|
||||||
);
|
|
||||||
if (!c.moveToNext())
|
|
||||||
throw new IllegalStateException();
|
|
||||||
long serviceID = c.getLong(0);
|
|
||||||
|
|
||||||
AccountSettings settings = new AccountSettings(getContext(), account);
|
AccountSettings settings = new AccountSettings(getContext(), account);
|
||||||
HttpUrl principal = HttpUrl.get(settings.getUri());
|
HttpUrl principal = HttpUrl.get(settings.getUri());
|
||||||
@ -167,8 +159,7 @@ public class CreateCollectionFragment extends DialogFragment implements LoaderMa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. add collection to service
|
// 2. add collection to service
|
||||||
EntityDataStore<Persistable> data = ((App) getContext().getApplicationContext()).getData();
|
info.serviceID = serviceEntity.getId();
|
||||||
info.serviceID = serviceID;
|
|
||||||
JournalEntity journalEntity = JournalEntity.fetchOrCreate(data, info);
|
JournalEntity journalEntity = JournalEntity.fetchOrCreate(data, info);
|
||||||
data.upsert(journalEntity);
|
data.upsert(journalEntity);
|
||||||
|
|
||||||
@ -180,8 +171,6 @@ public class CreateCollectionFragment extends DialogFragment implements LoaderMa
|
|||||||
return e;
|
return e;
|
||||||
} catch (Exceptions.IntegrityException|Exceptions.GenericCryptoException e) {
|
} catch (Exceptions.IntegrityException|Exceptions.GenericCryptoException e) {
|
||||||
return e;
|
return e;
|
||||||
} finally {
|
|
||||||
dbHelper.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -49,6 +49,7 @@ import com.etesync.syncadapter.journalmanager.Exceptions.HttpException;
|
|||||||
import com.etesync.syncadapter.model.EntryEntity;
|
import com.etesync.syncadapter.model.EntryEntity;
|
||||||
import com.etesync.syncadapter.model.JournalEntity;
|
import com.etesync.syncadapter.model.JournalEntity;
|
||||||
import com.etesync.syncadapter.model.ServiceDB;
|
import com.etesync.syncadapter.model.ServiceDB;
|
||||||
|
import com.etesync.syncadapter.model.ServiceEntity;
|
||||||
|
|
||||||
import io.requery.Persistable;
|
import io.requery.Persistable;
|
||||||
import io.requery.sql.EntityDataStore;
|
import io.requery.sql.EntityDataStore;
|
||||||
@ -246,8 +247,14 @@ public class DebugInfoActivity extends AppCompatActivity implements LoaderManage
|
|||||||
dbHelper.dump(report);
|
dbHelper.dump(report);
|
||||||
report.append("\n");
|
report.append("\n");
|
||||||
|
|
||||||
report.append("JOURNALS DUMP\n");
|
report.append("SERVICES DUMP\n");
|
||||||
EntityDataStore<Persistable> data = ((App) getContext().getApplicationContext()).getData();
|
EntityDataStore<Persistable> data = ((App) getContext().getApplicationContext()).getData();
|
||||||
|
for (ServiceEntity serviceEntity : data.select(ServiceEntity.class).get()) {
|
||||||
|
report.append(serviceEntity.toString() + "\n");
|
||||||
|
}
|
||||||
|
report.append("\n");
|
||||||
|
|
||||||
|
report.append("JOURNALS DUMP\n");
|
||||||
List<JournalEntity> journals = data.select(JournalEntity.class).where(JournalEntity.DELETED.eq(false)).get().toList();
|
List<JournalEntity> journals = data.select(JournalEntity.class).where(JournalEntity.DELETED.eq(false)).get().toList();
|
||||||
for (JournalEntity journal : journals) {
|
for (JournalEntity journal : journals) {
|
||||||
report.append(journal.toString() + "\n");
|
report.append(journal.toString() + "\n");
|
||||||
|
@ -123,7 +123,7 @@ public class DeleteCollectionFragment extends DialogFragment implements LoaderMa
|
|||||||
Crypto.CryptoManager crypto = new Crypto.CryptoManager(collectionInfo.version, settings.password(), collectionInfo.uid);
|
Crypto.CryptoManager crypto = new Crypto.CryptoManager(collectionInfo.version, settings.password(), collectionInfo.uid);
|
||||||
|
|
||||||
journalManager.deleteJournal(new JournalManager.Journal(crypto, collectionInfo.toJson(), collectionInfo.uid));
|
journalManager.deleteJournal(new JournalManager.Journal(crypto, collectionInfo.toJson(), collectionInfo.uid));
|
||||||
JournalEntity journalEntity = JournalEntity.fetch(data, collectionInfo.uid);
|
JournalEntity journalEntity = JournalEntity.fetch(data, collectionInfo.getServiceEntity(data), collectionInfo.uid);
|
||||||
journalEntity.setDeleted(true);
|
journalEntity.setDeleted(true);
|
||||||
data.update(journalEntity);
|
data.update(journalEntity);
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ public class EditCollectionActivity extends CreateCollectionActivity {
|
|||||||
|
|
||||||
public void onDeleteCollection(MenuItem item) {
|
public void onDeleteCollection(MenuItem item) {
|
||||||
EntityDataStore<Persistable> data = ((App) getApplication()).getData();
|
EntityDataStore<Persistable> data = ((App) getApplication()).getData();
|
||||||
int journalCount = data.count(JournalEntity.class).where(JournalEntity.SERVICE.eq(info.serviceID)).get().value();
|
int journalCount = data.count(JournalEntity.class).where(JournalEntity.SERVICE_MODEL.eq(info.getServiceEntity(data))).get().value();
|
||||||
|
|
||||||
if (journalCount < 2) {
|
if (journalCount < 2) {
|
||||||
new AlertDialog.Builder(this)
|
new AlertDialog.Builder(this)
|
||||||
|
@ -27,6 +27,8 @@ import com.etesync.syncadapter.R;
|
|||||||
import com.etesync.syncadapter.model.CollectionInfo;
|
import com.etesync.syncadapter.model.CollectionInfo;
|
||||||
import com.etesync.syncadapter.model.EntryEntity;
|
import com.etesync.syncadapter.model.EntryEntity;
|
||||||
import com.etesync.syncadapter.model.JournalEntity;
|
import com.etesync.syncadapter.model.JournalEntity;
|
||||||
|
import com.etesync.syncadapter.model.JournalModel;
|
||||||
|
import com.etesync.syncadapter.model.ServiceEntity;
|
||||||
import com.etesync.syncadapter.resource.LocalAddressBook;
|
import com.etesync.syncadapter.resource.LocalAddressBook;
|
||||||
import com.etesync.syncadapter.resource.LocalCalendar;
|
import com.etesync.syncadapter.resource.LocalCalendar;
|
||||||
import com.etesync.syncadapter.ui.importlocal.ImportActivity;
|
import com.etesync.syncadapter.ui.importlocal.ImportActivity;
|
||||||
@ -63,7 +65,7 @@ public class ViewCollectionActivity extends AppCompatActivity implements Refresh
|
|||||||
public void refresh() {
|
public void refresh() {
|
||||||
EntityDataStore<Persistable> data = ((App) getApplicationContext()).getData();
|
EntityDataStore<Persistable> data = ((App) getApplicationContext()).getData();
|
||||||
|
|
||||||
final JournalEntity journalEntity = JournalEntity.fetch(data, info.uid);
|
final JournalEntity journalEntity = JournalEntity.fetch(data, info.getServiceEntity(data), info.uid);
|
||||||
if ((journalEntity == null) || journalEntity.isDeleted()) {
|
if ((journalEntity == null) || journalEntity.isDeleted()) {
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
@ -173,7 +175,7 @@ public class ViewCollectionActivity extends AppCompatActivity implements Refresh
|
|||||||
protected Long doInBackground(Void... aVoids) {
|
protected Long doInBackground(Void... aVoids) {
|
||||||
EntityDataStore<Persistable> data = ((App) getApplicationContext()).getData();
|
EntityDataStore<Persistable> data = ((App) getApplicationContext()).getData();
|
||||||
|
|
||||||
final JournalEntity journalEntity = JournalEntity.fetch(data, info.uid);
|
final JournalEntity journalEntity = JournalEntity.fetch(data, info.getServiceEntity(data), info.uid);
|
||||||
|
|
||||||
entryCount = data.count(EntryEntity.class).where(EntryEntity.JOURNAL.eq(journalEntity)).get().value();
|
entryCount = data.count(EntryEntity.class).where(EntryEntity.JOURNAL.eq(journalEntity)).get().value();
|
||||||
long count;
|
long count;
|
||||||
|
@ -137,7 +137,7 @@ public class ListEntriesFragment extends ListFragment implements AdapterView.OnI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<EntryEntity> doInBackground(Void... voids) {
|
protected List<EntryEntity> doInBackground(Void... voids) {
|
||||||
journalEntity = JournalModel.Journal.fetch(data, info.uid);
|
journalEntity = JournalModel.Journal.fetch(data, info.getServiceEntity(data), info.uid);
|
||||||
return data.select(EntryEntity.class).where(EntryEntity.JOURNAL.eq(journalEntity)).orderBy(EntryEntity.ID.desc()).get().toList();
|
return data.select(EntryEntity.class).where(EntryEntity.JOURNAL.eq(journalEntity)).orderBy(EntryEntity.ID.desc()).get().toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ import android.app.Activity;
|
|||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@ -26,8 +25,6 @@ import android.support.v4.app.LoaderManager;
|
|||||||
import android.support.v4.content.AsyncTaskLoader;
|
import android.support.v4.content.AsyncTaskLoader;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import com.etesync.syncadapter.AccountSettings;
|
import com.etesync.syncadapter.AccountSettings;
|
||||||
import com.etesync.syncadapter.App;
|
import com.etesync.syncadapter.App;
|
||||||
import com.etesync.syncadapter.Constants;
|
import com.etesync.syncadapter.Constants;
|
||||||
@ -37,8 +34,12 @@ import com.etesync.syncadapter.journalmanager.Crypto;
|
|||||||
import com.etesync.syncadapter.model.CollectionInfo;
|
import com.etesync.syncadapter.model.CollectionInfo;
|
||||||
import com.etesync.syncadapter.model.JournalEntity;
|
import com.etesync.syncadapter.model.JournalEntity;
|
||||||
import com.etesync.syncadapter.model.ServiceDB;
|
import com.etesync.syncadapter.model.ServiceDB;
|
||||||
|
import com.etesync.syncadapter.model.ServiceEntity;
|
||||||
import com.etesync.syncadapter.resource.LocalTaskList;
|
import com.etesync.syncadapter.resource.LocalTaskList;
|
||||||
import com.etesync.syncadapter.ui.setup.BaseConfigurationFinder.Configuration;
|
import com.etesync.syncadapter.ui.setup.BaseConfigurationFinder.Configuration;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import at.bitfire.ical4android.TaskProvider;
|
import at.bitfire.ical4android.TaskProvider;
|
||||||
import io.requery.Persistable;
|
import io.requery.Persistable;
|
||||||
import io.requery.sql.EntityDataStore;
|
import io.requery.sql.EntityDataStore;
|
||||||
@ -140,7 +141,7 @@ public class SetupEncryptionFragment extends DialogFragment implements LoaderMan
|
|||||||
|
|
||||||
if (config.cardDAV != null) {
|
if (config.cardDAV != null) {
|
||||||
// insert CardDAV service
|
// insert CardDAV service
|
||||||
insertService(db, accountName, ServiceDB.Services.SERVICE_CARDDAV, config.cardDAV);
|
insertService(db, accountName, CollectionInfo.Type.ADDRESS_BOOK, config.cardDAV);
|
||||||
|
|
||||||
// contact sync is automatically enabled by isAlwaysSyncable="true" in res/xml/sync_contacts.xml
|
// contact sync is automatically enabled by isAlwaysSyncable="true" in res/xml/sync_contacts.xml
|
||||||
settings.setSyncInterval(ContactsContract.AUTHORITY, Constants.DEFAULT_SYNC_INTERVAL);
|
settings.setSyncInterval(ContactsContract.AUTHORITY, Constants.DEFAULT_SYNC_INTERVAL);
|
||||||
@ -150,7 +151,7 @@ public class SetupEncryptionFragment extends DialogFragment implements LoaderMan
|
|||||||
|
|
||||||
if (config.calDAV != null) {
|
if (config.calDAV != null) {
|
||||||
// insert CalDAV service
|
// insert CalDAV service
|
||||||
insertService(db, accountName, ServiceDB.Services.SERVICE_CALDAV, config.calDAV);
|
insertService(db, accountName, CollectionInfo.Type.CALENDAR, config.calDAV);
|
||||||
|
|
||||||
// calendar sync is automatically enabled by isAlwaysSyncable="true" in res/xml/sync_contacts.xml
|
// calendar sync is automatically enabled by isAlwaysSyncable="true" in res/xml/sync_contacts.xml
|
||||||
settings.setSyncInterval(CalendarContract.AUTHORITY, Constants.DEFAULT_SYNC_INTERVAL);
|
settings.setSyncInterval(CalendarContract.AUTHORITY, Constants.DEFAULT_SYNC_INTERVAL);
|
||||||
@ -172,22 +173,20 @@ public class SetupEncryptionFragment extends DialogFragment implements LoaderMan
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected long insertService(SQLiteDatabase db, String accountName, String service, BaseConfigurationFinder.Configuration.ServiceInfo info) {
|
protected void insertService(SQLiteDatabase db, String accountName, CollectionInfo.Type serviceType, BaseConfigurationFinder.Configuration.ServiceInfo info) {
|
||||||
ContentValues values = new ContentValues();
|
EntityDataStore<Persistable> data = ((App) getContext().getApplicationContext()).getData();
|
||||||
|
|
||||||
// insert service
|
// insert service
|
||||||
values.put(ServiceDB.Services.ACCOUNT_NAME, accountName);
|
ServiceEntity serviceEntity = new ServiceEntity();
|
||||||
values.put(ServiceDB.Services.SERVICE, service);
|
serviceEntity.setAccount(accountName);
|
||||||
long serviceID = db.insertWithOnConflict(ServiceDB.Services._TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
|
serviceEntity.setType(serviceType);
|
||||||
EntityDataStore<Persistable> data = ((App) getContext().getApplicationContext()).getData();
|
data.upsert(serviceEntity);
|
||||||
|
|
||||||
// insert collections
|
// insert collections
|
||||||
for (CollectionInfo collection : info.collections.values()) {
|
for (CollectionInfo collection : info.collections.values()) {
|
||||||
collection.serviceID = serviceID;
|
collection.serviceID = serviceEntity.getId();
|
||||||
JournalEntity journalEntity = new JournalEntity(collection);
|
JournalEntity journalEntity = new JournalEntity(data, collection);
|
||||||
data.insert(journalEntity);
|
data.insert(journalEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
return serviceID;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user