1
0
mirror of https://github.com/etesync/android synced 2024-11-22 07:58:09 +00:00

Unify all of the sync adapter exception handling.

The exception handling was duplicated across every sync backend.
It was redundant and made it easy to not handle all of the exceptions correctly
everywhere.
This commit is contained in:
Tom Hacohen 2019-05-01 09:23:19 +01:00
parent 6250cacd30
commit 2615fbd9ce
5 changed files with 123 additions and 216 deletions

View File

@ -40,14 +40,10 @@ class AddressBooksSyncAdapterService : SyncAdapterService() {
private class AddressBooksSyncAdapter(context: Context) : SyncAdapterService.SyncAdapter(context) {
override val syncErrorTitle = R.string.sync_error_contacts
override val notificationManager = SyncNotification(context, "journals-contacts", Constants.NOTIFICATION_CONTACTS_SYNC)
override fun onPerformSync(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
super.onPerformSync(account, extras, authority, provider, syncResult)
val notificationManager = SyncNotification(context, "journals-contacts", Constants.NOTIFICATION_CONTACTS_SYNC)
notificationManager.cancel()
try {
override fun onPerformSyncDo(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
val contactsProvider = context.contentResolver.acquireContentProviderClient(ContactsContract.AUTHORITY)
if (contactsProvider == null) {
Logger.log.severe("Couldn't access contacts provider")
@ -73,38 +69,6 @@ class AddressBooksSyncAdapterService : SyncAdapterService() {
syncExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true)
ContentResolver.requestSync(addressBookAccount, ContactsContract.AUTHORITY, syncExtras)
}
} catch (e: Exceptions.ServiceUnavailableException) {
syncResult.stats.numIoExceptions++
syncResult.delayUntil = if (e.retryAfter > 0) e.retryAfter else Constants.DEFAULT_RETRY_DELAY
} catch (e: Exceptions.IgnorableHttpException) {
// Ignore
} catch (e: Exception) {
if (e is ContactsStorageException || e is SQLiteException) {
Logger.log.log(Level.SEVERE, "Couldn't prepare local address books", e)
syncResult.databaseError = true
}
val syncPhase = R.string.sync_phase_journals
val title = context.getString(R.string.sync_error_contacts, account.name)
notificationManager.setThrowable(e)
val detailsIntent = notificationManager.detailsIntent
detailsIntent.putExtra(KEY_ACCOUNT, account)
if (e !is Exceptions.UnauthorizedException) {
detailsIntent.putExtra(DebugInfoActivity.KEY_AUTHORITY, authority)
detailsIntent.putExtra(DebugInfoActivity.KEY_PHASE, syncPhase)
}
notificationManager.notify(title, context.getString(syncPhase))
} catch (e: OutOfMemoryError) {
val syncPhase = R.string.sync_phase_journals
val title = context.getString(R.string.sync_error_contacts, account.name)
notificationManager.setThrowable(e)
val detailsIntent = notificationManager.detailsIntent
detailsIntent.putExtra(KEY_ACCOUNT, account)
notificationManager.notify(title, context.getString(syncPhase))
}
Logger.log.info("Address book sync complete")
}

View File

@ -31,21 +31,16 @@ import java.util.*
import java.util.logging.Level
class CalendarsSyncAdapterService : SyncAdapterService() {
override fun syncAdapter(): AbstractThreadedSyncAdapter {
return SyncAdapter(this)
}
private class SyncAdapter(context: Context) : SyncAdapterService.SyncAdapter(context) {
override val syncErrorTitle = R.string.sync_error_calendar
override val notificationManager = SyncNotification(context, "journals-calendar", Constants.NOTIFICATION_CALENDAR_SYNC)
override fun onPerformSync(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
super.onPerformSync(account, extras, authority, provider, syncResult)
val notificationManager = SyncNotification(context, "journals-calendar", Constants.NOTIFICATION_CALENDAR_SYNC)
notificationManager.cancel()
try {
override fun onPerformSyncDo(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
val settings = AccountSettings(context, account)
if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(settings))
return
@ -62,38 +57,6 @@ class CalendarsSyncAdapterService : SyncAdapterService() {
it.performSync()
}
}
} catch (e: Exceptions.ServiceUnavailableException) {
syncResult.stats.numIoExceptions++
syncResult.delayUntil = if (e.retryAfter > 0) e.retryAfter else Constants.DEFAULT_RETRY_DELAY
} catch (e: Exceptions.IgnorableHttpException) {
// Ignore
} catch (e: Exception) {
if (e is CalendarStorageException || e is SQLiteException) {
Logger.log.log(Level.SEVERE, "Couldn't prepare local calendars", e)
syncResult.databaseError = true
}
val syncPhase = R.string.sync_phase_journals
val title = context.getString(R.string.sync_error_calendar, account.name)
notificationManager.setThrowable(e)
val detailsIntent = notificationManager.detailsIntent
detailsIntent.putExtra(KEY_ACCOUNT, account)
if (e !is Exceptions.UnauthorizedException) {
detailsIntent.putExtra(DebugInfoActivity.KEY_AUTHORITY, authority)
detailsIntent.putExtra(DebugInfoActivity.KEY_PHASE, syncPhase)
}
notificationManager.notify(title, context.getString(syncPhase))
} catch (e: OutOfMemoryError) {
val syncPhase = R.string.sync_phase_journals
val title = context.getString(R.string.sync_error_calendar, account.name)
notificationManager.setThrowable(e)
val detailsIntent = notificationManager.detailsIntent
detailsIntent.putExtra(KEY_ACCOUNT, account)
notificationManager.notify(title, context.getString(syncPhase))
}
Logger.log.info("Calendar sync complete")
}

View File

@ -30,13 +30,10 @@ class ContactsSyncAdapterService : SyncAdapterService() {
private class ContactsSyncAdapter(context: Context) : SyncAdapterService.SyncAdapter(context) {
override val syncErrorTitle = R.string.sync_error_contacts
override val notificationManager = SyncNotification(context, "journals-contacts", Constants.NOTIFICATION_CONTACTS_SYNC)
override fun onPerformSync(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
super.onPerformSync(account, extras, authority, provider, syncResult)
val notificationManager = SyncNotification(context, "journals-contacts", Constants.NOTIFICATION_CONTACTS_SYNC)
notificationManager.cancel()
try {
override fun onPerformSyncDo(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
val addressBook = LocalAddressBook(context, account, provider)
val settings: AccountSettings
@ -62,32 +59,6 @@ class ContactsSyncAdapterService : SyncAdapterService() {
ContactsSyncManager(context, account, settings, extras, authority, provider, syncResult, addressBook, principal).use {
it.performSync()
}
} catch (e: Exceptions.ServiceUnavailableException) {
syncResult.stats.numIoExceptions++
syncResult.delayUntil = if (e.retryAfter > 0) e.retryAfter else Constants.DEFAULT_RETRY_DELAY
} catch (e: Exceptions.IgnorableHttpException) {
// Ignore
} catch (e: Exception) {
val syncPhase = R.string.sync_phase_journals
val title = context.getString(R.string.sync_error_contacts, account.name)
notificationManager.setThrowable(e)
val detailsIntent = notificationManager.detailsIntent
detailsIntent.putExtra(KEY_ACCOUNT, account)
if (e !is Exceptions.UnauthorizedException) {
detailsIntent.putExtra(DebugInfoActivity.KEY_AUTHORITY, authority)
detailsIntent.putExtra(DebugInfoActivity.KEY_PHASE, syncPhase)
}
notificationManager.notify(title, context.getString(syncPhase))
} catch (e: OutOfMemoryError) {
val syncPhase = R.string.sync_phase_journals
val title = context.getString(R.string.sync_error_contacts, account.name)
notificationManager.setThrowable(e)
val detailsIntent = notificationManager.detailsIntent
detailsIntent.putExtra(KEY_ACCOUNT, account)
notificationManager.notify(title, context.getString(syncPhase))
}
Logger.log.info("Contacts sync complete")
}

View File

@ -12,6 +12,7 @@ import android.accounts.Account
import android.app.PendingIntent
import android.app.Service
import android.content.*
import android.database.sqlite.SQLiteException
import android.net.ConnectivityManager
import android.net.wifi.WifiManager
import android.os.Bundle
@ -19,6 +20,8 @@ import android.os.IBinder
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.util.Pair
import at.bitfire.ical4android.CalendarStorageException
import at.bitfire.vcard4android.ContactsStorageException
import com.etesync.syncadapter.*
import com.etesync.syncadapter.journalmanager.Crypto
import com.etesync.syncadapter.journalmanager.Exceptions
@ -27,6 +30,7 @@ import com.etesync.syncadapter.log.Logger
import com.etesync.syncadapter.model.CollectionInfo
import com.etesync.syncadapter.model.JournalEntity
import com.etesync.syncadapter.model.JournalModel
import com.etesync.syncadapter.ui.DebugInfoActivity
import com.etesync.syncadapter.ui.PermissionsActivity
import com.etesync.syncadapter.utils.NotificationUtils
import okhttp3.HttpUrl
@ -45,12 +49,53 @@ abstract class SyncAdapterService : Service() {
abstract class SyncAdapter(context: Context) : AbstractThreadedSyncAdapter(context, false) {
abstract val syncErrorTitle: Int
abstract val notificationManager: SyncNotification
abstract fun onPerformSyncDo(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult)
override fun onPerformSync(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
Logger.log.log(Level.INFO, "$authority sync of $account has been initiated.", extras.keySet().toTypedArray())
// required for dav4android (ServiceLoader)
Thread.currentThread().contextClassLoader = context.classLoader
notificationManager.cancel()
try {
onPerformSyncDo(account, extras, authority, provider, syncResult)
} catch (e: Exceptions.ServiceUnavailableException) {
syncResult.stats.numIoExceptions++
syncResult.delayUntil = if (e.retryAfter > 0) e.retryAfter else Constants.DEFAULT_RETRY_DELAY
} catch (e: Exceptions.IgnorableHttpException) {
// Ignore
} catch (e: Exception) {
if (e is ContactsStorageException || e is CalendarStorageException || e is SQLiteException) {
Logger.log.log(Level.SEVERE, "Couldn't prepare local journals", e)
syncResult.databaseError = true
}
val syncPhase = R.string.sync_phase_journals
val title = context.getString(syncErrorTitle, account.name)
notificationManager.setThrowable(e)
val detailsIntent = notificationManager.detailsIntent
detailsIntent.putExtra(Constants.KEY_ACCOUNT, account)
if (e !is Exceptions.UnauthorizedException) {
detailsIntent.putExtra(DebugInfoActivity.KEY_AUTHORITY, authority)
detailsIntent.putExtra(DebugInfoActivity.KEY_PHASE, syncPhase)
}
notificationManager.notify(title, context.getString(syncPhase))
} catch (e: OutOfMemoryError) {
val syncPhase = R.string.sync_phase_journals
val title = context.getString(syncErrorTitle, account.name)
notificationManager.setThrowable(e)
val detailsIntent = notificationManager.detailsIntent
detailsIntent.putExtra(Constants.KEY_ACCOUNT, account)
notificationManager.notify(title, context.getString(syncPhase))
}
}
override fun onSecurityException(account: Account, extras: Bundle, authority: String, syncResult: SyncResult) {

View File

@ -45,14 +45,11 @@ class TasksSyncAdapterService: SyncAdapterService() {
class TasksSyncAdapter(
context: Context
): SyncAdapter(context) {
override val syncErrorTitle = R.string.sync_error_tasks
override val notificationManager = SyncNotification(context, "journals-tasks", Constants.NOTIFICATION_TASK_SYNC)
override fun onPerformSync(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
super.onPerformSync(account, extras, authority, provider, syncResult)
override fun onPerformSyncDo(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
val notificationManager = SyncNotification(context, "journals-tasks", Constants.NOTIFICATION_TASK_SYNC)
notificationManager.cancel()
try {
val taskProvider = TaskProvider.fromProviderClient(context, provider)
// make sure account can be seen by OpenTasks
@ -67,7 +64,6 @@ class TasksSyncAdapterService: SyncAdapterService() {
if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(accountSettings))
return
RefreshCollections(account, CollectionInfo.Type.TASKS).run()
updateLocalTaskLists(taskProvider, account, accountSettings)
@ -80,38 +76,6 @@ class TasksSyncAdapterService: SyncAdapterService() {
it.performSync()
}
}
} catch (e: Exceptions.ServiceUnavailableException) {
syncResult.stats.numIoExceptions++
syncResult.delayUntil = if (e.retryAfter > 0) e.retryAfter else Constants.DEFAULT_RETRY_DELAY
} catch (e: Exceptions.IgnorableHttpException) {
// Ignore
} catch (e: Exception) {
if (e is SQLiteException) {
Logger.log.log(Level.SEVERE, "Couldn't prepare local task list", e)
syncResult.databaseError = true
}
val syncPhase = R.string.sync_phase_journals
val title = context.getString(R.string.sync_error_tasks, account.name)
notificationManager.setThrowable(e)
val detailsIntent = notificationManager.detailsIntent
detailsIntent.putExtra(Constants.KEY_ACCOUNT, account)
if (e !is Exceptions.UnauthorizedException) {
detailsIntent.putExtra(DebugInfoActivity.KEY_AUTHORITY, authority)
detailsIntent.putExtra(DebugInfoActivity.KEY_PHASE, syncPhase)
}
notificationManager.notify(title, context.getString(syncPhase))
} catch (e: OutOfMemoryError) {
val syncPhase = R.string.sync_phase_journals
val title = context.getString(R.string.sync_error_tasks, account.name)
notificationManager.setThrowable(e)
val detailsIntent = notificationManager.detailsIntent
detailsIntent.putExtra(Constants.KEY_ACCOUNT, account)
notificationManager.notify(title, context.getString(syncPhase))
}
Logger.log.info("Task sync complete")
}