1
0
mirror of https://github.com/etesync/android synced 2025-05-11 11:28:50 +00:00

Check for migrations only when package is replaced, DB fixes

* AccountSettings$AppUpdatedReceiver: check for migrations only when package is replaced
* SyncAdapter: move DB helper from service to SyncAdapter to prevent databases from being closed too early
* Manual sync button: run sync immediately (without queueing)
This commit is contained in:
Ricki Hirner 2016-04-05 16:52:43 +02:00
parent 25c54cce62
commit 7ab13d648e
7 changed files with 150 additions and 130 deletions

View File

@ -60,6 +60,14 @@
<action android:name="at.bitfire.davdroid.REINIT_LOGGER"/> <action android:name="at.bitfire.davdroid.REINIT_LOGGER"/>
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver
android:name=".AccountSettings$AppUpdatedReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<data android:scheme="package" android:path="at.bitfire.davdroid" />
</intent-filter>
</receiver>
<service <service
android:name=".syncadapter.AccountAuthenticatorService" android:name=".syncadapter.AccountAuthenticatorService"

View File

@ -11,28 +11,23 @@ import android.accounts.Account;
import android.accounts.AccountManager; import android.accounts.AccountManager;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.ContentProviderClient; import android.content.ContentProviderClient;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.PeriodicSync; import android.content.PeriodicSync;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.provider.CalendarContract; import android.provider.CalendarContract;
import android.provider.CalendarContract.Calendars;
import android.provider.ContactsContract; import android.provider.ContactsContract;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v7.app.NotificationCompat; import android.support.v7.app.NotificationCompat;
import android.text.TextUtils; import android.text.TextUtils;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -362,4 +357,24 @@ public class AccountSettings {
accountManager.setUserData(account, KEY_SETTINGS_VERSION, "3"); accountManager.setUserData(account, KEY_SETTINGS_VERSION, "3");
} }
public static class AppUpdatedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
App.log.info("DAVdroid was updated, checking for AccountSettings version");
// peek into AccountSettings to initiate a possible migration
AccountManager accountManager = AccountManager.get(context);
for (Account account : accountManager.getAccountsByType(Constants.ACCOUNT_TYPE))
try {
App.log.info("Checking account " + account.name);
new AccountSettings(context, account);
} catch (InvalidAccountException e) {
App.log.log(Level.SEVERE, "Couldn't check for updated account settings", e);
}
}
}
} }

View File

@ -8,6 +8,7 @@
package at.bitfire.davdroid.syncadapter; package at.bitfire.davdroid.syncadapter;
import android.accounts.Account; import android.accounts.Account;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient; import android.content.ContentProviderClient;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context; import android.content.Context;
@ -15,6 +16,7 @@ import android.content.SyncResult;
import android.database.Cursor; import android.database.Cursor;
import android.database.DatabaseUtils; import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle; import android.os.Bundle;
import android.provider.CalendarContract; import android.provider.CalendarContract;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
@ -28,6 +30,7 @@ import at.bitfire.davdroid.AccountSettings;
import at.bitfire.davdroid.App; import at.bitfire.davdroid.App;
import at.bitfire.davdroid.InvalidAccountException; import at.bitfire.davdroid.InvalidAccountException;
import at.bitfire.davdroid.model.CollectionInfo; import at.bitfire.davdroid.model.CollectionInfo;
import at.bitfire.davdroid.model.ServiceDB;
import at.bitfire.davdroid.model.ServiceDB.Collections; import at.bitfire.davdroid.model.ServiceDB.Collections;
import at.bitfire.davdroid.model.ServiceDB.Services; import at.bitfire.davdroid.model.ServiceDB.Services;
import at.bitfire.davdroid.resource.LocalCalendar; import at.bitfire.davdroid.resource.LocalCalendar;
@ -37,16 +40,15 @@ import lombok.Cleanup;
public class CalendarsSyncAdapterService extends SyncAdapterService { public class CalendarsSyncAdapterService extends SyncAdapterService {
@Override @Override
public void onCreate() { protected AbstractThreadedSyncAdapter syncAdapter() {
super.onCreate(); return new SyncAdapter(this);
syncAdapter = new SyncAdapter(this, dbHelper.getReadableDatabase());
} }
private static class SyncAdapter extends SyncAdapterService.SyncAdapter { private static class SyncAdapter extends SyncAdapterService.SyncAdapter {
public SyncAdapter(Context context, SQLiteDatabase db) { public SyncAdapter(Context context) {
super(context, db); super(context);
} }
@Override @Override
@ -72,40 +74,47 @@ public class CalendarsSyncAdapterService extends SyncAdapterService {
} }
private void updateLocalCalendars(ContentProviderClient provider, Account account) throws CalendarStorageException, InvalidAccountException { private void updateLocalCalendars(ContentProviderClient provider, Account account) throws CalendarStorageException, InvalidAccountException {
// enumerate remote and local calendars SQLiteOpenHelper dbHelper = new ServiceDB.OpenHelper(getContext());
Long service = getService(account); try {
Map<String, CollectionInfo> remote = remoteCalendars(service); // enumerate remote and local calendars
LocalCalendar[] local = (LocalCalendar[])LocalCalendar.find(account, provider, LocalCalendar.Factory.INSTANCE, null, null); SQLiteDatabase db = dbHelper.getReadableDatabase();
Long service = getService(db, account);
Map<String, CollectionInfo> remote = remoteCalendars(db, service);
AccountSettings settings = new AccountSettings(getContext(), account); LocalCalendar[] local = (LocalCalendar[])LocalCalendar.find(account, provider, LocalCalendar.Factory.INSTANCE, null, null);
boolean updateColors = settings.getManageCalendarColors();
// delete obsolete local calendar AccountSettings settings = new AccountSettings(getContext(), account);
for (LocalCalendar calendar : local) { boolean updateColors = settings.getManageCalendarColors();
String url = calendar.getName();
if (!remote.containsKey(url)) { // delete obsolete local calendar
App.log.fine("Deleting obsolete local calendar " + url); for (LocalCalendar calendar : local) {
calendar.delete(); String url = calendar.getName();
} else { if (!remote.containsKey(url)) {
// remote CollectionInfo found for this local collection, update data App.log.fine("Deleting obsolete local calendar " + url);
CollectionInfo info = remote.get(url); calendar.delete();
App.log.fine("Updating local calendar " + url + " with " + info); } else {
calendar.update(info, updateColors); // remote CollectionInfo found for this local collection, update data
// we already have a local calendar for this remote collection, don't take into consideration anymore CollectionInfo info = remote.get(url);
remote.remove(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 // create new local calendars
for (String url : remote.keySet()) { 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.info("Adding local calendar list " + info);
LocalCalendar.create(account, provider, info); LocalCalendar.create(account, provider, info);
}
} finally {
dbHelper.close();
} }
} }
@Nullable @Nullable
Long getService(Account account) { Long getService(@NonNull SQLiteDatabase db, @NonNull Account account) {
@Cleanup Cursor c = db.query(Services._TABLE, new String[] { Services.ID }, @Cleanup Cursor c = db.query(Services._TABLE, new String[] { Services.ID },
Services.ACCOUNT_NAME + "=? AND " + Services.SERVICE + "=?", new String[] { account.name, Services.SERVICE_CALDAV }, null, null, null); Services.ACCOUNT_NAME + "=? AND " + Services.SERVICE + "=?", new String[] { account.name, Services.SERVICE_CALDAV }, null, null, null);
if (c.moveToNext()) if (c.moveToNext())
@ -115,7 +124,7 @@ public class CalendarsSyncAdapterService extends SyncAdapterService {
} }
@NonNull @NonNull
private Map<String, CollectionInfo> remoteCalendars(Long service) { private Map<String, CollectionInfo> remoteCalendars(@NonNull SQLiteDatabase db, Long service) {
Map<String, CollectionInfo> collections = new LinkedHashMap<>(); Map<String, CollectionInfo> collections = new LinkedHashMap<>();
if (service != null) { if (service != null) {
@Cleanup Cursor cursor = db.query(Collections._TABLE, null, @Cleanup Cursor cursor = db.query(Collections._TABLE, null,

View File

@ -8,6 +8,7 @@
package at.bitfire.davdroid.syncadapter; package at.bitfire.davdroid.syncadapter;
import android.accounts.Account; import android.accounts.Account;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient; import android.content.ContentProviderClient;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context; import android.content.Context;
@ -15,6 +16,7 @@ import android.content.SyncResult;
import android.database.Cursor; import android.database.Cursor;
import android.database.DatabaseUtils; import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -30,43 +32,48 @@ import lombok.Cleanup;
public class ContactsSyncAdapterService extends SyncAdapterService { public class ContactsSyncAdapterService extends SyncAdapterService {
@Override @Override
public void onCreate() { protected AbstractThreadedSyncAdapter syncAdapter() {
super.onCreate(); return new ContactsSyncAdapter(this);
syncAdapter = new ContactsSyncAdapter(this, dbHelper.getReadableDatabase()); }
}
private static class ContactsSyncAdapter extends SyncAdapter { private static class ContactsSyncAdapter extends SyncAdapter {
public ContactsSyncAdapter(Context context, SQLiteDatabase db) { public ContactsSyncAdapter(Context context) {
super(context, db); super(context);
} }
@Override @Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
super.onPerformSync(account, extras, authority, provider, syncResult); super.onPerformSync(account, extras, authority, provider, syncResult);
Long service = getService(account); SQLiteOpenHelper dbHelper = new ServiceDB.OpenHelper(getContext());
if (service != null) { try {
CollectionInfo remote = remoteAddressBook(service); SQLiteDatabase db = dbHelper.getReadableDatabase();
if (remote != null) Long service = getService(db, account);
try { if (service != null) {
ContactsSyncManager syncManager = new ContactsSyncManager(getContext(), account, extras, authority, provider, syncResult, remote); CollectionInfo remote = remoteAddressBook(db, service);
syncManager.performSync(); if (remote != null)
} catch (InvalidAccountException e) { try {
App.log.log(Level.SEVERE, "Couldn't get account settings", e); ContactsSyncManager syncManager = new ContactsSyncManager(getContext(), account, extras, authority, provider, syncResult, remote);
} syncManager.performSync();
else } catch(InvalidAccountException e) {
App.log.info("No address book collection selected for synchronization"); App.log.log(Level.SEVERE, "Couldn't get account settings", e);
} else }
App.log.info("No CardDAV service found in DB"); else
App.log.info("No address book collection selected for synchronization");
} else
App.log.info("No CardDAV service found in DB");
} finally {
dbHelper.close();
}
App.log.info("Address book sync complete"); App.log.info("Address book sync complete");
} }
@Nullable @Nullable
private Long getService(@NonNull Account account) { private Long getService(@NonNull SQLiteDatabase db, @NonNull Account account) {
@Cleanup Cursor c = db.query(ServiceDB.Services._TABLE, new String[] { ServiceDB.Services.ID }, @Cleanup Cursor c = db.query(ServiceDB.Services._TABLE, new String[] { ServiceDB.Services.ID },
ServiceDB.Services.ACCOUNT_NAME + "=? AND " + ServiceDB.Services.SERVICE + "=?", new String[] { account.name, ServiceDB.Services.SERVICE_CARDDAV }, null, null, null); ServiceDB.Services.ACCOUNT_NAME + "=? AND " + ServiceDB.Services.SERVICE + "=?", new String[] { account.name, ServiceDB.Services.SERVICE_CARDDAV }, null, null, null);
if (c.moveToNext()) if (c.moveToNext())
@ -76,7 +83,7 @@ public class ContactsSyncAdapterService extends SyncAdapterService {
} }
@Nullable @Nullable
private CollectionInfo remoteAddressBook(long service) { private CollectionInfo remoteAddressBook(@NonNull SQLiteDatabase db, long service) {
@Cleanup Cursor c = db.query(Collections._TABLE, null, @Cleanup Cursor c = db.query(Collections._TABLE, null,
Collections.SERVICE_ID + "=? AND " + Collections.SYNC, new String[] { String.valueOf(service) }, null, null, null); Collections.SERVICE_ID + "=? AND " + Collections.SYNC, new String[] { String.valueOf(service) }, null, null, null);
if (c.moveToNext()) { if (c.moveToNext()) {

View File

@ -29,33 +29,19 @@ import at.bitfire.davdroid.model.ServiceDB;
public abstract class SyncAdapterService extends Service { public abstract class SyncAdapterService extends Service {
ServiceDB.OpenHelper dbHelper; abstract protected AbstractThreadedSyncAdapter syncAdapter();
AbstractThreadedSyncAdapter syncAdapter;
@Override
public void onCreate() {
dbHelper = new ServiceDB.OpenHelper(this);
}
@Override
public void onDestroy() {
dbHelper.close();
}
@Nullable @Nullable
@Override @Override
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
return syncAdapter.getSyncAdapterBinder(); return syncAdapter().getSyncAdapterBinder();
} }
public static abstract class SyncAdapter extends AbstractThreadedSyncAdapter { public static abstract class SyncAdapter extends AbstractThreadedSyncAdapter {
protected final SQLiteDatabase db; // will be closed in SyncAdapterService::onDestroy(), don't close manually! public SyncAdapter(Context context) {
public SyncAdapter(Context context, SQLiteDatabase db) {
super(context, false); super(context, false);
this.db = db;
} }
@Override @Override
@ -64,13 +50,6 @@ public abstract class SyncAdapterService extends Service {
// required for dav4android (ServiceLoader) // required for dav4android (ServiceLoader)
Thread.currentThread().setContextClassLoader(getContext().getClassLoader()); Thread.currentThread().setContextClassLoader(getContext().getClassLoader());
// peek into AccountSettings to cause possible migration (v0.9 -> v1.0)
try {
new AccountSettings(getContext(), account);
} catch (InvalidAccountException e) {
App.log.log(Level.SEVERE, "Couldn't check for updated account settings", e);
}
} }
} }

View File

@ -8,6 +8,7 @@
package at.bitfire.davdroid.syncadapter; package at.bitfire.davdroid.syncadapter;
import android.accounts.Account; import android.accounts.Account;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient; import android.content.ContentProviderClient;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context; import android.content.Context;
@ -15,6 +16,7 @@ import android.content.SyncResult;
import android.database.Cursor; import android.database.Cursor;
import android.database.DatabaseUtils; import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -26,6 +28,7 @@ import java.util.logging.Level;
import at.bitfire.davdroid.App; import at.bitfire.davdroid.App;
import at.bitfire.davdroid.InvalidAccountException; import at.bitfire.davdroid.InvalidAccountException;
import at.bitfire.davdroid.model.CollectionInfo; import at.bitfire.davdroid.model.CollectionInfo;
import at.bitfire.davdroid.model.ServiceDB;
import at.bitfire.davdroid.model.ServiceDB.Collections; import at.bitfire.davdroid.model.ServiceDB.Collections;
import at.bitfire.davdroid.model.ServiceDB.Services; import at.bitfire.davdroid.model.ServiceDB.Services;
import at.bitfire.davdroid.resource.LocalTaskList; import at.bitfire.davdroid.resource.LocalTaskList;
@ -35,17 +38,16 @@ import lombok.Cleanup;
public class TasksSyncAdapterService extends SyncAdapterService { public class TasksSyncAdapterService extends SyncAdapterService {
@Override @Override
public void onCreate() { protected AbstractThreadedSyncAdapter syncAdapter() {
super.onCreate(); return new SyncAdapter(this);
syncAdapter = new SyncAdapter(this, dbHelper.getReadableDatabase()); }
}
private static class SyncAdapter extends SyncAdapterService.SyncAdapter { private static class SyncAdapter extends SyncAdapterService.SyncAdapter {
public SyncAdapter(Context context, SQLiteDatabase db) { public SyncAdapter(Context context) {
super(context, db); super(context);
} }
@Override @Override
@ -74,37 +76,43 @@ public class TasksSyncAdapterService extends SyncAdapterService {
} }
private void updateLocalTaskLists(TaskProvider provider, Account account) throws CalendarStorageException { private void updateLocalTaskLists(TaskProvider provider, Account account) throws CalendarStorageException {
// enumerate remote and local task lists SQLiteOpenHelper dbHelper = new ServiceDB.OpenHelper(getContext());
Long service = getService(account); try {
Map<String, CollectionInfo> remote = remoteTaskLists(service); // enumerate remote and local task lists
LocalTaskList[] local = (LocalTaskList[])LocalTaskList.find(account, provider, LocalTaskList.Factory.INSTANCE, null, null); SQLiteDatabase db = dbHelper.getReadableDatabase();
Long service = getService(db, account);
Map<String, CollectionInfo> remote = remoteTaskLists(db, service);
LocalTaskList[] local = (LocalTaskList[])LocalTaskList.find(account, provider, LocalTaskList.Factory.INSTANCE, null, null);
// delete obsolete local task lists // delete obsolete local task lists
for (LocalTaskList list : local) { for (LocalTaskList list : local) {
String url = list.getSyncId(); String url = list.getSyncId();
if (!remote.containsKey(url)) { if (!remote.containsKey(url)) {
App.log.fine("Deleting obsolete local task list" + url); App.log.fine("Deleting obsolete local task list" + url);
list.delete(); list.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); CollectionInfo info = remote.get(url);
App.log.fine("Updating local task list " + url + " with " + info); App.log.fine("Updating local task list " + url + " with " + info);
list.update(info); list.update(info);
// we already have a local task list for this remote collection, don't take into consideration anymore // we already have a local task list for this remote collection, don't take into consideration anymore
remote.remove(url); remote.remove(url);
}
} }
}
// create new local task lists // create new local task lists
for (String url : remote.keySet()) { for (String url : remote.keySet()) {
CollectionInfo info = remote.get(url); CollectionInfo info = remote.get(url);
App.log.info("Adding local task list " + info); App.log.info("Adding local task list " + info);
LocalTaskList.create(account, provider, info); LocalTaskList.create(account, provider, info);
}
} finally {
dbHelper.close();
} }
} }
@Nullable @Nullable
Long getService(Account account) { Long getService(@NonNull SQLiteDatabase db, @NonNull Account account) {
@Cleanup Cursor c = db.query(Services._TABLE, new String[] { Services.ID }, @Cleanup Cursor c = db.query(Services._TABLE, new String[] { Services.ID },
Services.ACCOUNT_NAME + "=? AND " + Services.SERVICE + "=?", new String[] { account.name, Services.SERVICE_CALDAV }, null, null, null); Services.ACCOUNT_NAME + "=? AND " + Services.SERVICE + "=?", new String[] { account.name, Services.SERVICE_CALDAV }, null, null, null);
if (c.moveToNext()) if (c.moveToNext())
@ -114,7 +122,7 @@ public class TasksSyncAdapterService extends SyncAdapterService {
} }
@NonNull @NonNull
private Map<String, CollectionInfo> remoteTaskLists(Long service) { private Map<String, CollectionInfo> remoteTaskLists(@NonNull SQLiteDatabase db, Long service) {
Map<String, CollectionInfo> collections = new LinkedHashMap<>(); Map<String, CollectionInfo> collections = new LinkedHashMap<>();
if (service != null) { if (service != null) {
@Cleanup Cursor cursor = db.query(Collections._TABLE, null, @Cleanup Cursor cursor = db.query(Collections._TABLE, null,

View File

@ -62,11 +62,8 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import at.bitfire.davdroid.AccountSettings;
import at.bitfire.davdroid.App; import at.bitfire.davdroid.App;
import at.bitfire.davdroid.Constants;
import at.bitfire.davdroid.DavService; import at.bitfire.davdroid.DavService;
import at.bitfire.davdroid.InvalidAccountException;
import at.bitfire.davdroid.R; import at.bitfire.davdroid.R;
import at.bitfire.davdroid.model.CollectionInfo; import at.bitfire.davdroid.model.CollectionInfo;
import at.bitfire.davdroid.model.ServiceDB; import at.bitfire.davdroid.model.ServiceDB;
@ -373,15 +370,6 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
@Override @Override
public AccountInfo loadInBackground() { public AccountInfo loadInBackground() {
// peek into AccountSettings to call possible 0.9 -> 1.0 migration
// The next line can be removed as soon as migration from 0.9 is not required anymore!
try {
new AccountSettings(getContext(), new Account(accountName, Constants.ACCOUNT_TYPE));
} catch (InvalidAccountException e) {
App.log.log(Level.INFO, "Account doesn't exist (anymore)", e);
return null;
}
AccountInfo info = new AccountInfo(); AccountInfo info = new AccountInfo();
try { try {
SQLiteDatabase db = dbHelper.getReadableDatabase(); SQLiteDatabase db = dbHelper.getReadableDatabase();
@ -391,6 +379,11 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
new String[] { Services.ID, Services.SERVICE }, new String[] { Services.ID, Services.SERVICE },
Services.ACCOUNT_NAME + "=?", new String[] { accountName }, Services.ACCOUNT_NAME + "=?", new String[] { accountName },
null, null, null); null, null, null);
if (cursor.getCount() == 0)
// no services, account not useable
return null;
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
long id = cursor.getLong(0); long id = cursor.getLong(0);
String service = cursor.getString(1); String service = cursor.getString(1);
@ -557,7 +550,8 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
for (String authority : authorities) { for (String authority : authorities) {
Bundle extras = new Bundle(); Bundle extras = new Bundle();
extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); // manual sync
extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); // run immediately (don't queue)
ContentResolver.requestSync(account, authority, extras); ContentResolver.requestSync(account, authority, extras);
} }