diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e7c9dc60..130c25e0 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -91,6 +91,54 @@
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/account_authenticator"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
sqlAccountNames = new LinkedList<>();
+ List accountNames = new LinkedList<>();
AccountManager am = AccountManager.get(this);
- for (Account account : am.getAccountsByType(Constants.ACCOUNT_TYPE))
- sqlAccountNames.add(account.name);
+ for (Account account : am.getAccountsByType(App.getAccountType())) {
+ accountNames.add(account.name);
+ }
EntityDataStore data = ((App) getApplication()).getData();
- if (sqlAccountNames.isEmpty()) {
+ // delete orphaned address book accounts
+ for (Account addrBookAccount : am.getAccountsByType(App.getAddressBookAccountType())) {
+ LocalAddressBook addressBook = new LocalAddressBook(this, addrBookAccount, null);
+ try {
+ if (!accountNames.contains(addressBook.getMainAccount().name))
+ addressBook.delete();
+ } catch(ContactsStorageException e) {
+ App.log.log(Level.SEVERE, "Couldn't get address book main account", e);
+ }
+ }
+
+
+ if (accountNames.isEmpty()) {
data.delete(ServiceEntity.class).get().value();
} else {
- data.delete(ServiceEntity.class).where(ServiceEntity.ACCOUNT.notIn(sqlAccountNames)).get().value();
+ data.delete(ServiceEntity.class).where(ServiceEntity.ACCOUNT.notIn(accountNames)).get().value();
}
}
}
diff --git a/app/src/main/java/com/etesync/syncadapter/App.java b/app/src/main/java/com/etesync/syncadapter/App.java
index 7b95c3c3..3d759535 100644
--- a/app/src/main/java/com/etesync/syncadapter/App.java
+++ b/app/src/main/java/com/etesync/syncadapter/App.java
@@ -107,6 +107,13 @@ public class App extends Application {
at.bitfire.cert4android.Constants.log = Logger.getLogger("syncadapter.cert4android");
}
+ @Getter
+ private static String accountType;
+ @Getter
+ private static String addressBookAccountType;
+ @Getter
+ private static String addressBooksAuthority;
+
@Override
@SuppressLint("HardwareIds")
public void onCreate() {
@@ -117,6 +124,10 @@ public class App extends Application {
initPrefVersion();
uidGenerator = new UidGenerator(null, android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID));
+
+ accountType = getString(R.string.account_type);
+ addressBookAccountType = getString(R.string.account_type_address_book);
+ addressBooksAuthority = getString(R.string.address_books_authority);
}
public void reinitCertManager() {
@@ -301,16 +312,21 @@ public class App extends Application {
AccountManager am = AccountManager.get(this);
for (Account account : am.getAccountsByType(Constants.ACCOUNT_TYPE)) {
try {
+ // Generate account settings to make sure account is migrated.
+ new AccountSettings(this, account);
+
LocalCalendar calendars[] = (LocalCalendar[]) LocalCalendar.find(account, this.getContentResolver().acquireContentProviderClient(CalendarContract.CONTENT_URI),
LocalCalendar.Factory.INSTANCE, null, null);
for (LocalCalendar calendar : calendars) {
calendar.fixEtags();
}
- } catch (CalendarStorageException e) {
+ } catch (CalendarStorageException|InvalidAccountException e) {
e.printStackTrace();
}
+ }
- LocalAddressBook addressBook = new LocalAddressBook(account, this.getContentResolver().acquireContentProviderClient(ContactsContract.Contacts.CONTENT_URI));
+ for (Account account : am.getAccountsByType(App.getAddressBookAccountType())) {
+ LocalAddressBook addressBook = new LocalAddressBook(this, account, this.getContentResolver().acquireContentProviderClient(ContactsContract.Contacts.CONTENT_URI));
try {
addressBook.fixEtags();
} catch (ContactsStorageException e) {
diff --git a/app/src/main/java/com/etesync/syncadapter/HttpClient.java b/app/src/main/java/com/etesync/syncadapter/HttpClient.java
index 5fd080a8..d6454974 100644
--- a/app/src/main/java/com/etesync/syncadapter/HttpClient.java
+++ b/app/src/main/java/com/etesync/syncadapter/HttpClient.java
@@ -56,9 +56,7 @@ public class HttpClient {
return builder.build();
}
- public static OkHttpClient create(@Nullable Context context, @NonNull Account account, @NonNull final Logger logger) throws InvalidAccountException {
- // use account settings for authentication
- AccountSettings settings = new AccountSettings(context, account);
+ public static OkHttpClient create(@Nullable Context context, @NonNull AccountSettings settings, @NonNull final Logger logger) throws InvalidAccountException {
return create(context, logger, Constants.serviceUrl.getHost(), settings.getAuthToken());
}
@@ -66,8 +64,8 @@ public class HttpClient {
return defaultBuilder(context, logger).build();
}
- public static OkHttpClient create(@NonNull Context context, @NonNull Account account) throws InvalidAccountException {
- return create(context, account, App.log);
+ public static OkHttpClient create(@NonNull Context context, @NonNull AccountSettings settings) throws InvalidAccountException {
+ return create(context, settings, App.log);
}
public static OkHttpClient create(@Nullable Context context) {
diff --git a/app/src/main/java/com/etesync/syncadapter/resource/LocalAddressBook.java b/app/src/main/java/com/etesync/syncadapter/resource/LocalAddressBook.java
index d6b8e8ca..b0aaf092 100644
--- a/app/src/main/java/com/etesync/syncadapter/resource/LocalAddressBook.java
+++ b/app/src/main/java/com/etesync/syncadapter/resource/LocalAddressBook.java
@@ -8,25 +8,35 @@
package com.etesync.syncadapter.resource;
import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
+import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.os.Parcel;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
import android.provider.ContactsContract.Groups;
import android.provider.ContactsContract.RawContacts;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.os.OperationCanceledException;
import com.etesync.syncadapter.App;
+import com.etesync.syncadapter.model.CollectionInfo;
+import com.etesync.syncadapter.utils.Base64;
+import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
+import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
@@ -45,9 +55,11 @@ import lombok.Cleanup;
public class LocalAddressBook extends AndroidAddressBook implements LocalCollection {
protected static final String
- SYNC_STATE_CTAG = "ctag",
- SYNC_STATE_URL = "url";
+ USER_DATA_MAIN_ACCOUNT_TYPE = "real_account_type",
+ USER_DATA_MAIN_ACCOUNT_NAME = "real_account_name",
+ USER_DATA_URL = "url";
+ protected final Context context;
private final Bundle syncState = new Bundle();
/**
@@ -58,8 +70,70 @@ public class LocalAddressBook extends AndroidAddressBook implements LocalCollect
public boolean includeGroups = true;
- public LocalAddressBook(Account account, ContentProviderClient provider) {
+ public static LocalAddressBook[] find(@NonNull Context context, @NonNull ContentProviderClient provider, @Nullable Account mainAccount) throws ContactsStorageException {
+ AccountManager accountManager = AccountManager.get(context);
+
+ List result = new LinkedList<>();
+ for (Account account : accountManager.getAccountsByType(App.getAddressBookAccountType())) {
+ LocalAddressBook addressBook = new LocalAddressBook(context, account, provider);
+ if (mainAccount == null || addressBook.getMainAccount().equals(mainAccount))
+ result.add(addressBook);
+ }
+
+ return result.toArray(new LocalAddressBook[result.size()]);
+ }
+
+ public static LocalAddressBook create(@NonNull Context context, @NonNull ContentProviderClient provider, @NonNull Account mainAccount, @NonNull CollectionInfo info) throws ContactsStorageException {
+ AccountManager accountManager = AccountManager.get(context);
+
+ Account account = new Account(accountName(mainAccount, info), App.getAddressBookAccountType());
+ if (!accountManager.addAccountExplicitly(account, null, initialUserData(mainAccount, info.uid)))
+ throw new ContactsStorageException("Couldn't create address book account");
+
+ LocalAddressBook addressBook = new LocalAddressBook(context, account, provider);
+ addressBook.setMainAccount(mainAccount);
+ addressBook.setURL(info.uid);
+
+ ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true);
+
+ return addressBook;
+ }
+
+ public void update(@NonNull CollectionInfo info) throws AuthenticatorException, OperationCanceledException, IOException, ContactsStorageException, android.accounts.OperationCanceledException {
+ final String newAccountName = accountName(getMainAccount(), info);
+ if (!account.name.equals(newAccountName) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ final AccountManager accountManager = AccountManager.get(context);
+ AccountManagerFuture future = accountManager.renameAccount(account, newAccountName, new AccountManagerCallback() {
+ @Override
+ public void run(AccountManagerFuture future) {
+ try {
+ // update raw contacts to new account name
+ if (provider != null) {
+ ContentValues values = new ContentValues(1);
+ values.put(RawContacts.ACCOUNT_NAME, newAccountName);
+ provider.update(syncAdapterURI(RawContacts.CONTENT_URI), values, RawContacts.ACCOUNT_NAME + "=? AND " + RawContacts.ACCOUNT_TYPE + "=?",
+ new String[] { account.name, account.type });
+ }
+ } catch(RemoteException e) {
+ App.log.log(Level.WARNING, "Couldn't re-assign contacts to new account name", e);
+ }
+ }
+ }, null);
+ account = future.getResult();
+ }
+
+ // make sure it will still be synchronized when contacts are updated
+ ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true);
+ }
+
+ public void delete() {
+ AccountManager accountManager = AccountManager.get(context);
+ accountManager.removeAccount(account, null, null);
+ }
+
+ public LocalAddressBook(Context context, Account account, ContentProviderClient provider) {
super(account, provider, LocalGroup.Factory.INSTANCE, LocalContact.Factory.INSTANCE);
+ this.context = context;
}
@NonNull
@@ -268,51 +342,53 @@ public class LocalAddressBook extends AndroidAddressBook implements LocalCollect
}
- // SYNC STATE
+ // SETTINGS
- @SuppressWarnings("ParcelClassLoader,Recycle")
- protected void readSyncState() throws ContactsStorageException {
- @Cleanup("recycle") Parcel parcel = Parcel.obtain();
- byte[] raw = getSyncState();
- syncState.clear();
- if (raw != null) {
- parcel.unmarshall(raw, 0, raw.length);
- parcel.setDataPosition(0);
- syncState.putAll(parcel.readBundle());
- }
+ public static Bundle initialUserData(@NonNull Account mainAccount, @NonNull String url) {
+ Bundle bundle = new Bundle(3);
+ bundle.putString(USER_DATA_MAIN_ACCOUNT_NAME, mainAccount.name);
+ bundle.putString(USER_DATA_MAIN_ACCOUNT_TYPE, mainAccount.type);
+ bundle.putString(USER_DATA_URL, url);
+ return bundle;
}
- @SuppressWarnings("Recycle")
- protected void writeSyncState() throws ContactsStorageException {
- @Cleanup("recycle") Parcel parcel = Parcel.obtain();
- parcel.writeBundle(syncState);
- setSyncState(parcel.marshall());
+ public Account getMainAccount() throws ContactsStorageException {
+ AccountManager accountManager = AccountManager.get(context);
+ String name = accountManager.getUserData(account, USER_DATA_MAIN_ACCOUNT_NAME),
+ type = accountManager.getUserData(account, USER_DATA_MAIN_ACCOUNT_TYPE);
+ if (name != null && type != null)
+ return new Account(name, type);
+ else
+ throw new ContactsStorageException("Address book doesn't exist anymore");
+ }
+
+ public void setMainAccount(@NonNull Account mainAccount) throws ContactsStorageException {
+ AccountManager accountManager = AccountManager.get(context);
+ accountManager.setUserData(account, USER_DATA_MAIN_ACCOUNT_NAME, mainAccount.name);
+ accountManager.setUserData(account, USER_DATA_MAIN_ACCOUNT_TYPE, mainAccount.type);
}
public String getURL() throws ContactsStorageException {
- synchronized (syncState) {
- readSyncState();
- return syncState.getString(SYNC_STATE_URL);
- }
+ AccountManager accountManager = AccountManager.get(context);
+ return accountManager.getUserData(account, USER_DATA_URL);
}
public void setURL(String url) throws ContactsStorageException {
- synchronized (syncState) {
- readSyncState();
- syncState.putString(SYNC_STATE_URL, url);
- writeSyncState();
- }
+ AccountManager accountManager = AccountManager.get(context);
+ accountManager.setUserData(account, USER_DATA_URL, url);
}
// HELPERS
- public static void onRenameAccount(@NonNull ContentResolver resolver, @NonNull String oldName, @NonNull String newName) throws RemoteException {
- @Cleanup("release") ContentProviderClient client = resolver.acquireContentProviderClient(ContactsContract.AUTHORITY);
- if (client != null) {
- ContentValues values = new ContentValues(1);
- values.put(RawContacts.ACCOUNT_NAME, newName);
- client.update(RawContacts.CONTENT_URI, values, RawContacts.ACCOUNT_NAME + "=?", new String[]{oldName});
- }
+ public static String accountName(@NonNull Account mainAccount, @NonNull CollectionInfo info) {
+ String displayName = (info.displayName != null) ? info.displayName : info.uid;
+ StringBuilder sb = new StringBuilder(displayName);
+ sb .append(" (")
+ .append(mainAccount.name)
+ .append(" ")
+ .append(info.uid.substring(0, 4))
+ .append(")");
+ return sb.toString();
}
/** Fix all of the etags of all of the non-dirty contacts to be non-null.
diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/AddressBookProvider.java b/app/src/main/java/com/etesync/syncadapter/syncadapter/AddressBookProvider.java
new file mode 100644
index 00000000..14bdf90d
--- /dev/null
+++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/AddressBookProvider.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 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.syncadapter;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+public class AddressBookProvider extends ContentProvider {
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getType(@NonNull Uri uri) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
+ return 0;
+ }
+
+}
diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/AddressBooksSyncAdapterService.java b/app/src/main/java/com/etesync/syncadapter/syncadapter/AddressBooksSyncAdapterService.java
new file mode 100644
index 00000000..ef5ed8ea
--- /dev/null
+++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/AddressBooksSyncAdapterService.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright © 2013 – 2015 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.syncadapter;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SyncResult;
+import android.database.sqlite.SQLiteException;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+
+import com.etesync.syncadapter.AccountSettings;
+import com.etesync.syncadapter.App;
+import com.etesync.syncadapter.Constants;
+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.JournalModel;
+import com.etesync.syncadapter.model.ServiceEntity;
+import com.etesync.syncadapter.resource.LocalAddressBook;
+import com.etesync.syncadapter.ui.DebugInfoActivity;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+
+import at.bitfire.vcard4android.ContactsStorageException;
+import io.requery.Persistable;
+import io.requery.sql.EntityDataStore;
+import lombok.Cleanup;
+
+import static com.etesync.syncadapter.Constants.KEY_ACCOUNT;
+
+public class AddressBooksSyncAdapterService extends SyncAdapterService {
+
+ @Override
+ protected AbstractThreadedSyncAdapter syncAdapter() {
+ return new AddressBooksSyncAdapter(this);
+ }
+
+
+ private static class AddressBooksSyncAdapter extends SyncAdapter {
+
+ public AddressBooksSyncAdapter(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
+ super.onPerformSync(account, extras, authority, provider, syncResult);
+
+ NotificationHelper notificationManager = new NotificationHelper(getContext(), "journals-contacts", Constants.NOTIFICATION_CONTACTS_SYNC);
+ notificationManager.cancel();
+
+ try {
+ @Cleanup("release") ContentProviderClient contactsProvider = getContext().getContentResolver().acquireContentProviderClient(ContactsContract.AUTHORITY);
+ if (contactsProvider == null) {
+ App.log.severe("Couldn't access contacts provider");
+ syncResult.databaseError = true;
+ return;
+ }
+
+ AccountSettings settings = new AccountSettings(getContext(), account);
+ if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(settings))
+ return;
+
+ new RefreshCollections(account, CollectionInfo.Type.ADDRESS_BOOK).run();
+
+ updateLocalAddressBooks(contactsProvider, account);
+
+ AccountManager accountManager = AccountManager.get(getContext());
+ for (Account addressBookAccount : accountManager.getAccountsByType(getContext().getString(R.string.account_type_address_book))) {
+ App.log.log(Level.INFO, "Running sync for address book", addressBookAccount);
+ Bundle syncExtras = new Bundle(extras);
+ syncExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
+ syncExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
+ ContentResolver.requestSync(addressBookAccount, ContactsContract.AUTHORITY, syncExtras);
+ }
+ } catch (Exceptions.ServiceUnavailableException e) {
+ syncResult.stats.numIoExceptions++;
+ syncResult.delayUntil = (e.retryAfter > 0) ? e.retryAfter : Constants.DEFAULT_RETRY_DELAY;
+ } catch (Exception | OutOfMemoryError e) {
+ if (e instanceof ContactsStorageException || e instanceof SQLiteException) {
+ App.log.log(Level.SEVERE, "Couldn't prepare local address books", e);
+ syncResult.databaseError = true;
+ }
+
+ int syncPhase = R.string.sync_phase_journals;
+ String title = getContext().getString(R.string.sync_error_contacts, account.name);
+
+ notificationManager.setThrowable(e);
+
+ final Intent detailsIntent = notificationManager.getDetailsIntent();
+ detailsIntent.putExtra(KEY_ACCOUNT, account);
+ if (!(e instanceof Exceptions.UnauthorizedException)) {
+ detailsIntent.putExtra(DebugInfoActivity.KEY_AUTHORITY, authority);
+ detailsIntent.putExtra(DebugInfoActivity.KEY_PHASE, syncPhase);
+ }
+
+ notificationManager.notify(title, getContext().getString(syncPhase));
+ }
+
+ App.log.info("Address book sync complete");
+ }
+
+
+ private void updateLocalAddressBooks(ContentProviderClient provider, Account account) throws ContactsStorageException, AuthenticatorException, OperationCanceledException, IOException {
+ final Context context = getContext();
+ EntityDataStore data = ((App) getContext().getApplicationContext()).getData();
+ ServiceEntity service = JournalModel.Service.fetch(data, account.name, CollectionInfo.Type.ADDRESS_BOOK);
+
+ Map remote = new HashMap<>();
+ List remoteJournals = JournalEntity.getJournals(data, service);
+ for (JournalEntity journalEntity : remoteJournals) {
+ remote.put(journalEntity.getUid(), journalEntity);
+ }
+
+ LocalAddressBook[] local = LocalAddressBook.find(context, provider, account);
+
+ // delete obsolete local address books
+ for (LocalAddressBook addressBook : local) {
+ String url = addressBook.getURL();
+ if (!remote.containsKey(url)) {
+ App.log.fine("Deleting obsolete local address book " + url);
+ addressBook.delete();
+ } else {
+ // remote CollectionInfo found for this local collection, update data
+ JournalEntity journalEntity = remote.get(url);
+ App.log.fine("Updating local address book " + url + " with " + journalEntity);
+ addressBook.update(journalEntity);
+ // we already have a local collection for this remote collection, don't take into consideration anymore
+ remote.remove(url);
+ }
+ }
+
+ // create new local address books
+ for (String url : remote.keySet()) {
+ JournalEntity journalEntity = remote.get(url);
+ App.log.info("Adding local address book " + journalEntity);
+ LocalAddressBook.create(context, provider, account, journalEntity);
+ }
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarSyncManager.java b/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarSyncManager.java
index de871b88..58712d84 100644
--- a/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarSyncManager.java
+++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/CalendarSyncManager.java
@@ -46,7 +46,7 @@ public class CalendarSyncManager extends SyncManager {
final private HttpUrl remote;
public CalendarSyncManager(Context context, Account account, AccountSettings settings, Bundle extras, String authority, SyncResult result, LocalCalendar calendar, HttpUrl remote) throws InvalidAccountException, Exceptions.IntegrityException, Exceptions.GenericCryptoException {
- super(context, account, settings, extras, authority, result, calendar.getName(), CollectionInfo.Type.CALENDAR);
+ super(context, account, settings, extras, authority, result, calendar.getName(), CollectionInfo.Type.CALENDAR, account.name);
localCollection = calendar;
this.remote = remote;
}
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 9c63c8a2..9ce8dc4e 100644
--- a/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncAdapterService.java
+++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncAdapterService.java
@@ -28,6 +28,7 @@ import com.etesync.syncadapter.model.JournalEntity;
import com.etesync.syncadapter.model.JournalModel;
import com.etesync.syncadapter.model.ServiceDB;
import com.etesync.syncadapter.model.ServiceEntity;
+import com.etesync.syncadapter.resource.LocalAddressBook;
import com.etesync.syncadapter.ui.DebugInfoActivity;
import java.util.logging.Level;
@@ -59,30 +60,18 @@ public class ContactsSyncAdapterService extends SyncAdapterService {
notificationManager.cancel();
try {
- AccountSettings settings = new AccountSettings(getContext(), account);
+ LocalAddressBook addressBook = new LocalAddressBook(getContext(), account, provider);
+
+ AccountSettings settings = new AccountSettings(getContext(), addressBook.getMainAccount());
if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(settings))
return;
- new RefreshCollections(account, CollectionInfo.Type.ADDRESS_BOOK).run();
+ App.log.info("Synchronizing address book: " + addressBook.getURL());
+ App.log.info("Taking settings from: " + addressBook.getMainAccount());
- EntityDataStore data = ((App) getContext().getApplicationContext()).getData();
-
- ServiceEntity service = JournalModel.Service.fetch(data, account.name, CollectionInfo.Type.ADDRESS_BOOK);
-
- if (service != null) {
- HttpUrl principal = HttpUrl.get(settings.getUri());
- CollectionInfo info = JournalEntity.getCollections(data, service).get(0);
- try {
- ContactsSyncManager syncManager = new ContactsSyncManager(getContext(), account, settings, extras, authority, provider, syncResult, principal, info);
- syncManager.performSync();
- } catch (InvalidAccountException e) {
- App.log.log(Level.SEVERE, "Couldn't get account settings", e);
- }
- } else
- App.log.info("No CardDAV service found in DB");
- } catch (Exceptions.ServiceUnavailableException e) {
- syncResult.stats.numIoExceptions++;
- syncResult.delayUntil = (e.retryAfter > 0) ? e.retryAfter : Constants.DEFAULT_RETRY_DELAY;
+ HttpUrl principal = HttpUrl.get(settings.getUri());
+ ContactsSyncManager syncManager = new ContactsSyncManager(getContext(), account, settings, extras, authority, provider, syncResult, addressBook, principal);
+ syncManager.performSync();
} catch (Exception | OutOfMemoryError e) {
int syncPhase = R.string.sync_phase_journals;
String title = getContext().getString(R.string.sync_error_contacts, account.name);
@@ -98,7 +87,7 @@ public class ContactsSyncAdapterService extends SyncAdapterService {
notificationManager.notify(title, getContext().getString(syncPhase));
}
- App.log.info("Address book sync complete");
+ App.log.info("Contacts sync complete");
}
}
diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncManager.java b/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncManager.java
index 2b6be832..57ad8e9b 100644
--- a/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncManager.java
+++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncManager.java
@@ -60,10 +60,12 @@ public class ContactsSyncManager extends SyncManager {
final private ContentProviderClient provider;
final private HttpUrl remote;
- public ContactsSyncManager(Context context, Account account, AccountSettings settings, Bundle extras, String authority, ContentProviderClient provider, SyncResult result, HttpUrl principal, CollectionInfo info) throws InvalidAccountException, Exceptions.IntegrityException, Exceptions.GenericCryptoException {
- super(context, account, settings, extras, authority, result, info.uid, CollectionInfo.Type.ADDRESS_BOOK);
+ public ContactsSyncManager(Context context, Account account, AccountSettings settings, Bundle extras, String authority, ContentProviderClient provider, SyncResult result, LocalAddressBook localAddressBook, HttpUrl principal) throws InvalidAccountException, Exceptions.IntegrityException, Exceptions.GenericCryptoException, ContactsStorageException {
+ super(context, account, settings, extras, authority, result, localAddressBook.getURL(), CollectionInfo.Type.ADDRESS_BOOK, localAddressBook.getMainAccount().name);
this.provider = provider;
this.remote = principal;
+
+ localCollection = localAddressBook;
}
@Override
@@ -80,10 +82,7 @@ public class ContactsSyncManager extends SyncManager {
protected boolean prepare() throws ContactsStorageException, CalendarStorageException {
if (!super.prepare())
return false;
- // prepare local address book
- localCollection = new LocalAddressBook(account, provider);
LocalAddressBook localAddressBook = localAddressBook();
- localAddressBook.setURL(info.uid);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// workaround for Android 7 which sets DIRTY flag when only meta-data is changed
@@ -101,7 +100,7 @@ public class ContactsSyncManager extends SyncManager {
values.put(ContactsContract.Settings.UNGROUPED_VISIBLE, 1);
localAddressBook.updateSettings(values);
- journal = new JournalEntryManager(httpClient, remote, info.uid);
+ journal = new JournalEntryManager(httpClient, remote, localAddressBook.getURL());
return true;
}
diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/NullAuthenticatorService.java b/app/src/main/java/com/etesync/syncadapter/syncadapter/NullAuthenticatorService.java
new file mode 100644
index 00000000..e85852cc
--- /dev/null
+++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/NullAuthenticatorService.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright © 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.syncadapter;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.NetworkErrorException;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+
+public class NullAuthenticatorService extends Service {
+
+ private AccountAuthenticator accountAuthenticator;
+
+ @Override
+ public void onCreate() {
+ accountAuthenticator = new NullAuthenticatorService.AccountAuthenticator(this);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (intent.getAction().equals(android.accounts.AccountManager.ACTION_AUTHENTICATOR_INTENT))
+ return accountAuthenticator.getIBinder();
+ return null;
+ }
+
+
+ private static class AccountAuthenticator extends AbstractAccountAuthenticator {
+ final Context context;
+
+ public AccountAuthenticator(Context context) {
+ super(context);
+ this.context = context;
+ }
+
+ @Override
+ public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
+ return null;
+ }
+
+ @Override
+ public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
+ return null;
+ }
+
+ @Override
+ public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
+ return null;
+ }
+
+ @Override
+ public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
+ return null;
+ }
+
+ @Override
+ public String getAuthTokenLabel(String authTokenType) {
+ return null;
+ }
+
+ @Override
+ public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
+ return null;
+ }
+
+ @Override
+ public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
+ return null;
+ }
+
+ }
+
+}
\ No newline at end of file
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 06946fc0..9b5a92f3 100644
--- a/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncAdapterService.java
+++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncAdapterService.java
@@ -76,7 +76,7 @@ public abstract class SyncAdapterService extends Service {
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
- App.log.log(Level.INFO, "Sync for " + authority + " has been initiated.", extras.keySet().toArray());
+ App.log.log(Level.INFO, authority + " sync of " + account + " has been initiated.", extras.keySet().toArray());
// required for dav4android (ServiceLoader)
Thread.currentThread().setContextClassLoader(getContext().getClassLoader());
@@ -143,9 +143,9 @@ public abstract class SyncAdapterService extends Service {
void run() throws Exceptions.HttpException, Exceptions.IntegrityException, InvalidAccountException, Exceptions.GenericCryptoException {
App.log.info("Refreshing " + serviceType + " collections of service #" + serviceType.toString());
- OkHttpClient httpClient = HttpClient.create(context, account);
-
AccountSettings settings = new AccountSettings(context, account);
+ OkHttpClient httpClient = HttpClient.create(context, settings);
+
JournalManager journalsManager = new JournalManager(httpClient, HttpUrl.get(settings.getUri()));
List> journals = new LinkedList<>();
diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncManager.java b/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncManager.java
index 45531db8..25067e1f 100644
--- a/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncManager.java
+++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncManager.java
@@ -97,7 +97,7 @@ abstract public class SyncManager {
private List localDeleted;
private LocalResource[] localDirty;
- public SyncManager(Context context, Account account, AccountSettings settings, Bundle extras, String authority, SyncResult syncResult, String journalUid, CollectionInfo.Type serviceType) throws InvalidAccountException, Exceptions.IntegrityException, Exceptions.GenericCryptoException {
+ public SyncManager(Context context, Account account, AccountSettings settings, Bundle extras, String authority, SyncResult syncResult, String journalUid, CollectionInfo.Type serviceType, String accountName) throws InvalidAccountException, Exceptions.IntegrityException, Exceptions.GenericCryptoException {
this.context = context;
this.account = account;
this.settings = settings;
@@ -107,10 +107,10 @@ abstract public class SyncManager {
this.serviceType = serviceType;
// create HttpClient with given logger
- httpClient = HttpClient.create(context, account);
+ httpClient = HttpClient.create(context, settings);
data = ((App) context.getApplicationContext()).getData();
- ServiceEntity serviceEntity = JournalModel.Service.fetch(data, account.name, serviceType);
+ ServiceEntity serviceEntity = JournalModel.Service.fetch(data, accountName, serviceType);
info = JournalEntity.fetch(data, serviceEntity, journalUid).getInfo();
// dismiss previous error notifications
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 ad091144..7c1ef284 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.java
@@ -58,6 +58,7 @@ import com.etesync.syncadapter.journalmanager.Crypto;
import com.etesync.syncadapter.model.CollectionInfo;
import com.etesync.syncadapter.model.JournalEntity;
import com.etesync.syncadapter.model.ServiceEntity;
+import com.etesync.syncadapter.resource.LocalAddressBook;
import com.etesync.syncadapter.resource.LocalCalendar;
import com.etesync.syncadapter.ui.setup.SetupUserInfoFragment;
import com.etesync.syncadapter.utils.HintManager;
@@ -69,6 +70,7 @@ import java.util.logging.Level;
import at.bitfire.cert4android.CustomCertManager;
import at.bitfire.ical4android.TaskProvider;
+import at.bitfire.vcard4android.ContactsStorageException;
import io.requery.Persistable;
import io.requery.sql.EntityDataStore;
import tourguide.tourguide.ToolTip;
@@ -357,8 +359,18 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
if (service.equals(CollectionInfo.Type.ADDRESS_BOOK)) {
info.carddav = new AccountInfo.ServiceInfo();
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, App.getAddressBooksAuthority());
info.carddav.journals = JournalEntity.getJournals(data, serviceEntity);
+
+ AccountManager accountManager = AccountManager.get(getContext());
+ for (Account addrBookAccount : accountManager.getAccountsByType(App.getAddressBookAccountType())) {
+ LocalAddressBook addressBook = new LocalAddressBook(getContext(), addrBookAccount, null);
+ try {
+ if (account.equals(addressBook.getMainAccount()))
+ info.carddav.refreshing |= ContentResolver.isSyncActive(addrBookAccount, ContactsContract.AUTHORITY);
+ } catch(ContactsStorageException e) {
+ }
+ }
} else if (service.equals(CollectionInfo.Type.CALENDAR)) {
info.caldav = new AccountInfo.ServiceInfo();
info.caldav.id = id;
@@ -457,7 +469,7 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
protected static void requestSync(Account account) {
String authorities[] = {
- ContactsContract.AUTHORITY,
+ App.getAddressBooksAuthority(),
CalendarContract.AUTHORITY,
TaskProvider.ProviderName.OpenTasks.authority
};
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/AccountSettingsActivity.java b/app/src/main/java/com/etesync/syncadapter/ui/AccountSettingsActivity.java
index d60377ad..ddc6e6f3 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/AccountSettingsActivity.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/AccountSettingsActivity.java
@@ -111,7 +111,7 @@ public class AccountSettingsActivity extends AppCompatActivity {
// category: synchronization
final ListPreference prefSyncContacts = (ListPreference)findPreference("sync_interval_contacts");
- final Long syncIntervalContacts = settings.getSyncInterval(ContactsContract.AUTHORITY);
+ final Long syncIntervalContacts = settings.getSyncInterval(App.getAddressBooksAuthority());
if (syncIntervalContacts != null) {
prefSyncContacts.setValue(syncIntervalContacts.toString());
if (syncIntervalContacts == AccountSettings.SYNC_INTERVAL_MANUALLY)
@@ -121,7 +121,7 @@ public class AccountSettingsActivity extends AppCompatActivity {
prefSyncContacts.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- settings.setSyncInterval(ContactsContract.AUTHORITY, Long.parseLong((String)newValue));
+ settings.setSyncInterval(App.getAddressBooksAuthority(), Long.parseLong((String)newValue));
getLoaderManager().restartLoader(0, getArguments(), AccountSettingsFragment.this);
return false;
}
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/AddMemberFragment.java b/app/src/main/java/com/etesync/syncadapter/ui/AddMemberFragment.java
index dae2ba6c..d3bbe91d 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/AddMemberFragment.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/AddMemberFragment.java
@@ -55,7 +55,7 @@ public class AddMemberFragment extends DialogFragment {
memberEmail = getArguments().getString(KEY_MEMBER);
try {
settings = new AccountSettings(getContext(), account);
- httpClient = HttpClient.create(getContext(), account);
+ httpClient = HttpClient.create(getContext(), settings);
} catch (InvalidAccountException e) {
e.printStackTrace();
}
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/CollectionMembersListFragment.java b/app/src/main/java/com/etesync/syncadapter/ui/CollectionMembersListFragment.java
index 73559d7b..b49aad06 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/CollectionMembersListFragment.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/CollectionMembersListFragment.java
@@ -130,8 +130,8 @@ public class CollectionMembersListFragment extends ListFragment implements Adapt
@Override
protected MembersResult doInBackground(Void... voids) {
try {
- OkHttpClient httpClient = HttpClient.create(getContext(), account);
AccountSettings settings = new AccountSettings(getContext(), account);
+ OkHttpClient httpClient = HttpClient.create(getContext(), settings);
JournalManager journalsManager = new JournalManager(httpClient, HttpUrl.get(settings.getUri()));
JournalManager.Journal journal = JournalManager.Journal.fakeWithUid(journalEntity.getUid());
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 5adb88aa..d23fc146 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionFragment.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionFragment.java
@@ -130,7 +130,7 @@ public class CreateCollectionFragment extends DialogFragment implements LoaderMa
// 1. find service ID
if (info.type == CollectionInfo.Type.ADDRESS_BOOK) {
- authority = ContactsContract.AUTHORITY;
+ authority = App.getAddressBooksAuthority();
} else if (info.type == CollectionInfo.Type.CALENDAR) {
authority = CalendarContract.AUTHORITY;
} else {
@@ -142,7 +142,7 @@ public class CreateCollectionFragment extends DialogFragment implements LoaderMa
AccountSettings settings = new AccountSettings(getContext(), account);
HttpUrl principal = HttpUrl.get(settings.getUri());
- JournalManager journalManager = new JournalManager(HttpClient.create(getContext(), account), principal);
+ JournalManager journalManager = new JournalManager(HttpClient.create(getContext(), settings), principal);
if (info.uid == null) {
info.uid = JournalManager.Journal.genUid();
Crypto.CryptoManager crypto = new Crypto.CryptoManager(info.version, settings.password(), info.uid);
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 cf5bed55..20606422 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/DeleteCollectionFragment.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/DeleteCollectionFragment.java
@@ -119,7 +119,7 @@ public class DeleteCollectionFragment extends DialogFragment implements LoaderMa
AccountSettings settings = new AccountSettings(getContext(), account);
HttpUrl principal = HttpUrl.get(settings.getUri());
- JournalManager journalManager = new JournalManager(HttpClient.create(getContext(), account), principal);
+ JournalManager journalManager = new JournalManager(HttpClient.create(getContext(), settings), principal);
Crypto.CryptoManager crypto = new Crypto.CryptoManager(collectionInfo.version, settings.password(), collectionInfo.uid);
journalManager.delete(new JournalManager.Journal(crypto, collectionInfo.toJson(), collectionInfo.uid));
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/RemoveMemberFragment.java b/app/src/main/java/com/etesync/syncadapter/ui/RemoveMemberFragment.java
index a8191238..e61799ee 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/RemoveMemberFragment.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/RemoveMemberFragment.java
@@ -52,7 +52,7 @@ public class RemoveMemberFragment extends DialogFragment {
memberEmail = getArguments().getString(KEY_MEMBER);
try {
settings = new AccountSettings(getContext(), account);
- httpClient = HttpClient.create(getContext(), account);
+ httpClient = HttpClient.create(getContext(), settings);
} catch (InvalidAccountException e) {
e.printStackTrace();
}
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/ViewCollectionActivity.java b/app/src/main/java/com/etesync/syncadapter/ui/ViewCollectionActivity.java
index 1a117511..783344a8 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/ViewCollectionActivity.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/ViewCollectionActivity.java
@@ -256,7 +256,7 @@ public class ViewCollectionActivity extends AppCompatActivity implements Refresh
}
} else {
try {
- LocalAddressBook resource = new LocalAddressBook(account, getContentResolver().acquireContentProviderClient(ContactsContract.Contacts.CONTENT_URI));
+ LocalAddressBook resource = new LocalAddressBook(ViewCollectionActivity.this, account, getContentResolver().acquireContentProviderClient(ContactsContract.Contacts.CONTENT_URI));
count = resource.count();
} catch (ContactsStorageException e) {
e.printStackTrace();
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/importlocal/ImportFragment.java b/app/src/main/java/com/etesync/syncadapter/ui/importlocal/ImportFragment.java
index 6b06b39f..c52f9f70 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/importlocal/ImportFragment.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/importlocal/ImportFragment.java
@@ -307,7 +307,7 @@ public class ImportFragment extends DialogFragment {
finishParsingFile(contacts.length);
ContentProviderClient provider = getContext().getContentResolver().acquireContentProviderClient(ContactsContract.RawContacts.CONTENT_URI);
- LocalAddressBook localAddressBook = new LocalAddressBook(account, provider);
+ LocalAddressBook localAddressBook = new LocalAddressBook(getContext(), account, provider);
for (Contact contact : contacts) {
try {
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/importlocal/LocalContactImportFragment.java b/app/src/main/java/com/etesync/syncadapter/ui/importlocal/LocalContactImportFragment.java
index dfa42309..74332951 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/importlocal/LocalContactImportFragment.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/importlocal/LocalContactImportFragment.java
@@ -104,7 +104,7 @@ public class LocalContactImportFragment extends Fragment {
String accountType = cursor.getString(accountTypeIndex);
if (account == null || (!account.name.equals(accountName) || !account.type.equals(accountType))) {
account = new Account(accountName, accountType);
- localAddressBooks.add(new LocalAddressBook(account, provider));
+ localAddressBooks.add(new LocalAddressBook(getContext(), account, provider));
}
}
@@ -152,7 +152,7 @@ public class LocalContactImportFragment extends Fragment {
private ResultFragment.ImportResult importContacts(LocalAddressBook localAddressBook) {
ResultFragment.ImportResult result = new ResultFragment.ImportResult();
try {
- LocalAddressBook addressBook = new LocalAddressBook(account,
+ LocalAddressBook addressBook = new LocalAddressBook(getContext(), account,
getContext().getContentResolver().acquireContentProviderClient(ContactsContract.RawContacts.CONTENT_URI));
LocalContact[] localContacts = localAddressBook.getAll();
int total = localContacts.length;
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 163b0682..e49fde38 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
@@ -171,9 +171,9 @@ public class SetupEncryptionFragment extends DialogFragment implements LoaderMan
insertService(accountName, CollectionInfo.Type.ADDRESS_BOOK, config.cardDAV);
// contact sync is automatically enabled by isAlwaysSyncable="true" in res/xml/sync_contacts.xml
- settings.setSyncInterval(ContactsContract.AUTHORITY, Constants.DEFAULT_SYNC_INTERVAL);
+ settings.setSyncInterval(App.getAddressBooksAuthority(), Constants.DEFAULT_SYNC_INTERVAL);
} else {
- ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 0);
+ ContentResolver.setIsSyncable(account, App.getAddressBooksAuthority(), 0);
}
if (config.calDAV != null) {
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/setup/SetupUserInfoFragment.java b/app/src/main/java/com/etesync/syncadapter/ui/setup/SetupUserInfoFragment.java
index 997f810c..c8953e9f 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/setup/SetupUserInfoFragment.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/setup/SetupUserInfoFragment.java
@@ -90,7 +90,7 @@ public class SetupUserInfoFragment extends DialogFragment {
protected SetupUserInfo.SetupUserInfoResult doInBackground(Account... accounts) {
try {
Crypto.CryptoManager cryptoManager;
- OkHttpClient httpClient = HttpClient.create(getContext(), account);
+ OkHttpClient httpClient = HttpClient.create(getContext(), settings);
UserInfoManager userInfoManager = new UserInfoManager(httpClient, HttpUrl.get(settings.getUri()));
UserInfoManager.UserInfo userInfo = userInfoManager.get(account.name);
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a061b759..4739e77f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -11,6 +11,11 @@
EteSync
+ com.etesync.syncadapter
+ com.etesync.syncadapter.address_book
+ EteSync Address book
+ com.etesync.syncadapter.addressbooks
+ Address books
Help
Manage accounts
Please wait …
diff --git a/app/src/main/res/xml/account_authenticator_address_book.xml b/app/src/main/res/xml/account_authenticator_address_book.xml
new file mode 100644
index 00000000..48979c31
--- /dev/null
+++ b/app/src/main/res/xml/account_authenticator_address_book.xml
@@ -0,0 +1,14 @@
+
+
+
diff --git a/app/src/main/res/xml/sync_address_books.xml b/app/src/main/res/xml/sync_address_books.xml
new file mode 100644
index 00000000..fea4886d
--- /dev/null
+++ b/app/src/main/res/xml/sync_address_books.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/app/src/main/res/xml/sync_contacts.xml b/app/src/main/res/xml/sync_contacts.xml
index 5d0e19fe..02f747e4 100644
--- a/app/src/main/res/xml/sync_contacts.xml
+++ b/app/src/main/res/xml/sync_contacts.xml
@@ -7,9 +7,9 @@
-->
+ android:userVisible="false"
+ android:isAlwaysSyncable="true" />
diff --git a/ical4android b/ical4android
index 2f6a94e8..49fbb684 160000
--- a/ical4android
+++ b/ical4android
@@ -1 +1 @@
-Subproject commit 2f6a94e85b9c0a375af8bdb08c8af82287c5fdc4
+Subproject commit 49fbb6846153fee5e5cbc71b77e94bef7629936d