mirror of
https://github.com/etesync/android
synced 2025-05-29 20:28:48 +00:00
Move everything to use the new Logger
This commit is contained in:
parent
216b51d138
commit
17b6e69c86
@ -20,6 +20,7 @@ import android.os.Bundle
|
|||||||
import at.bitfire.vcard4android.ContactsStorageException
|
import at.bitfire.vcard4android.ContactsStorageException
|
||||||
import at.bitfire.vcard4android.GroupMethod
|
import at.bitfire.vcard4android.GroupMethod
|
||||||
import com.etesync.syncadapter.journalmanager.Crypto
|
import com.etesync.syncadapter.journalmanager.Crypto
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.utils.Base64
|
import com.etesync.syncadapter.utils.Base64
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.net.URISyntaxException
|
import java.net.URISyntaxException
|
||||||
@ -110,7 +111,7 @@ constructor(internal val context: Context, internal val account: Account) {
|
|||||||
} catch (ignored: NumberFormatException) {
|
} catch (ignored: NumberFormatException) {
|
||||||
}
|
}
|
||||||
|
|
||||||
App.log.fine("Account " + account.name + " has version " + version + ", current version: " + CURRENT_VERSION)
|
Logger.log.fine("Account " + account.name + " has version " + version + ", current version: " + CURRENT_VERSION)
|
||||||
|
|
||||||
if (version < CURRENT_VERSION)
|
if (version < CURRENT_VERSION)
|
||||||
update(version)
|
update(version)
|
||||||
@ -168,12 +169,12 @@ constructor(internal val context: Context, internal val account: Account) {
|
|||||||
|
|
||||||
private fun update(fromVersion: Int) {
|
private fun update(fromVersion: Int) {
|
||||||
val toVersion = CURRENT_VERSION
|
val toVersion = CURRENT_VERSION
|
||||||
App.log.info("Updating account " + account.name + " from version " + fromVersion + " to " + toVersion)
|
Logger.log.info("Updating account " + account.name + " from version " + fromVersion + " to " + toVersion)
|
||||||
try {
|
try {
|
||||||
updateInner(fromVersion)
|
updateInner(fromVersion)
|
||||||
accountManager.setUserData(account, KEY_SETTINGS_VERSION, toVersion.toString())
|
accountManager.setUserData(account, KEY_SETTINGS_VERSION, toVersion.toString())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
App.log.log(Level.SEVERE, "Couldn't update account settings", e)
|
Logger.log.log(Level.SEVERE, "Couldn't update account settings", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -188,16 +189,16 @@ constructor(internal val context: Context, internal val account: Account) {
|
|||||||
|
|
||||||
@SuppressLint("UnsafeProtectedBroadcastReceiver,MissingPermission")
|
@SuppressLint("UnsafeProtectedBroadcastReceiver,MissingPermission")
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
App.log.info("EteSync was updated, checking for AccountSettings version")
|
Logger.log.info("EteSync was updated, checking for AccountSettings version")
|
||||||
|
|
||||||
// peek into AccountSettings to initiate a possible migration
|
// peek into AccountSettings to initiate a possible migration
|
||||||
val accountManager = AccountManager.get(context)
|
val accountManager = AccountManager.get(context)
|
||||||
for (account in accountManager.getAccountsByType(App.accountType))
|
for (account in accountManager.getAccountsByType(App.accountType))
|
||||||
try {
|
try {
|
||||||
App.log.info("Checking account " + account.name)
|
Logger.log.info("Checking account " + account.name)
|
||||||
AccountSettings(context, account)
|
AccountSettings(context, account)
|
||||||
} catch (e: InvalidAccountException) {
|
} catch (e: InvalidAccountException) {
|
||||||
App.log.log(Level.SEVERE, "Couldn't check for updated account settings", e)
|
Logger.log.log(Level.SEVERE, "Couldn't check for updated account settings", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import android.content.Intent
|
|||||||
import android.os.Binder
|
import android.os.Binder
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import at.bitfire.vcard4android.ContactsStorageException
|
import at.bitfire.vcard4android.ContactsStorageException
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.model.ServiceEntity
|
import com.etesync.syncadapter.model.ServiceEntity
|
||||||
import com.etesync.syncadapter.resource.LocalAddressBook
|
import com.etesync.syncadapter.resource.LocalAddressBook
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
@ -83,7 +84,7 @@ class AccountUpdateService : Service() {
|
|||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
internal fun cleanupAccounts() {
|
internal fun cleanupAccounts() {
|
||||||
App.log.info("Cleaning up orphaned accounts")
|
Logger.log.info("Cleaning up orphaned accounts")
|
||||||
|
|
||||||
val accountNames = LinkedList<String>()
|
val accountNames = LinkedList<String>()
|
||||||
val am = AccountManager.get(this)
|
val am = AccountManager.get(this)
|
||||||
@ -100,7 +101,7 @@ class AccountUpdateService : Service() {
|
|||||||
if (!accountNames.contains(addressBook.mainAccount.name))
|
if (!accountNames.contains(addressBook.mainAccount.name))
|
||||||
addressBook.delete()
|
addressBook.delete()
|
||||||
} catch (e: ContactsStorageException) {
|
} catch (e: ContactsStorageException) {
|
||||||
App.log.log(Level.SEVERE, "Couldn't get address book main account", e)
|
Logger.log.log(Level.SEVERE, "Couldn't get address book main account", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import android.accounts.OnAccountsUpdateListener
|
|||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class AccountsChangedReceiver : BroadcastReceiver() {
|
class AccountsChangedReceiver : BroadcastReceiver() {
|
||||||
@ -24,7 +25,7 @@ class AccountsChangedReceiver : BroadcastReceiver() {
|
|||||||
try {
|
try {
|
||||||
context.startService(serviceIntent)
|
context.startService(serviceIntent)
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
App.log.warning("Got an illegal state exception! Ignoring...")
|
Logger.log.warning("Got an illegal state exception! Ignoring...")
|
||||||
}
|
}
|
||||||
|
|
||||||
for (listener in listeners)
|
for (listener in listeners)
|
||||||
|
@ -18,20 +18,15 @@ import android.database.sqlite.SQLiteDatabase
|
|||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.drawable.BitmapDrawable
|
import android.graphics.drawable.BitmapDrawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Process
|
|
||||||
import android.os.StrictMode
|
import android.os.StrictMode
|
||||||
import android.provider.CalendarContract
|
import android.provider.CalendarContract
|
||||||
import android.provider.ContactsContract
|
import android.provider.ContactsContract
|
||||||
import androidx.core.app.NotificationCompat
|
|
||||||
import androidx.core.app.NotificationManagerCompat
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import android.util.Log
|
|
||||||
import at.bitfire.cert4android.CustomCertManager
|
import at.bitfire.cert4android.CustomCertManager
|
||||||
import at.bitfire.ical4android.AndroidCalendar
|
import at.bitfire.ical4android.AndroidCalendar
|
||||||
import at.bitfire.ical4android.CalendarStorageException
|
import at.bitfire.ical4android.CalendarStorageException
|
||||||
import at.bitfire.vcard4android.ContactsStorageException
|
import at.bitfire.vcard4android.ContactsStorageException
|
||||||
import com.etesync.syncadapter.log.LogcatHandler
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.log.PlainTextFormatter
|
|
||||||
import com.etesync.syncadapter.model.*
|
import com.etesync.syncadapter.model.*
|
||||||
import com.etesync.syncadapter.resource.LocalAddressBook
|
import com.etesync.syncadapter.resource.LocalAddressBook
|
||||||
import com.etesync.syncadapter.resource.LocalCalendar
|
import com.etesync.syncadapter.resource.LocalCalendar
|
||||||
@ -44,14 +39,8 @@ import io.requery.meta.EntityModel
|
|||||||
import io.requery.sql.EntityDataStore
|
import io.requery.sql.EntityDataStore
|
||||||
import okhttp3.internal.tls.OkHostnameVerifier
|
import okhttp3.internal.tls.OkHostnameVerifier
|
||||||
import org.acra.ACRA
|
import org.acra.ACRA
|
||||||
import org.apache.commons.lang3.time.DateFormatUtils
|
|
||||||
import org.jetbrains.anko.doAsync
|
import org.jetbrains.anko.doAsync
|
||||||
import java.io.File
|
|
||||||
import java.io.IOException
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.logging.FileHandler
|
|
||||||
import java.util.logging.Level
|
|
||||||
import java.util.logging.Logger
|
|
||||||
import javax.net.ssl.HostnameVerifier
|
import javax.net.ssl.HostnameVerifier
|
||||||
|
|
||||||
|
|
||||||
@ -145,72 +134,14 @@ class App : Application() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun reinitLogger() {
|
fun reinitLogger() {
|
||||||
val dbHelper = ServiceDB.OpenHelper(this)
|
Logger.initialize(this)
|
||||||
val settings = Settings(dbHelper.readableDatabase)
|
|
||||||
|
|
||||||
val logToFile = settings.getBoolean(LOG_TO_EXTERNAL_STORAGE, false)
|
|
||||||
val logVerbose = logToFile || Log.isLoggable(log.name, Log.DEBUG)
|
|
||||||
|
|
||||||
App.log.info("Verbose logging: $logVerbose")
|
|
||||||
|
|
||||||
// set logging level according to preferences
|
|
||||||
val rootLogger = Logger.getLogger("")
|
|
||||||
rootLogger.level = if (logVerbose) Level.ALL else Level.INFO
|
|
||||||
|
|
||||||
// remove all handlers and add our own logcat handler
|
|
||||||
rootLogger.useParentHandlers = false
|
|
||||||
for (handler in rootLogger.handlers)
|
|
||||||
rootLogger.removeHandler(handler)
|
|
||||||
rootLogger.addHandler(LogcatHandler)
|
|
||||||
|
|
||||||
val nm = NotificationManagerCompat.from(this)
|
|
||||||
// log to external file according to preferences
|
|
||||||
if (logToFile) {
|
|
||||||
val builder = NotificationCompat.Builder(this)
|
|
||||||
builder.setSmallIcon(R.drawable.ic_sd_storage_light)
|
|
||||||
.setLargeIcon(getLauncherBitmap(this))
|
|
||||||
.setContentTitle(getString(R.string.logging_davdroid_file_logging))
|
|
||||||
.setLocalOnly(true)
|
|
||||||
|
|
||||||
val dir = getExternalFilesDir(null)
|
|
||||||
if (dir != null)
|
|
||||||
try {
|
|
||||||
val fileName = File(dir, "etesync-" + Process.myPid() + "-" +
|
|
||||||
DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMdd-HHmmss") + ".txt").toString()
|
|
||||||
log.info("Logging to $fileName")
|
|
||||||
|
|
||||||
val fileHandler = FileHandler(fileName)
|
|
||||||
fileHandler.formatter = PlainTextFormatter.DEFAULT
|
|
||||||
log.addHandler(fileHandler)
|
|
||||||
builder.setContentText(dir.path)
|
|
||||||
.setSubText(getString(R.string.logging_to_external_storage_warning))
|
|
||||||
.setCategory(NotificationCompat.CATEGORY_STATUS)
|
|
||||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
|
||||||
.setStyle(NotificationCompat.BigTextStyle()
|
|
||||||
.bigText(getString(R.string.logging_to_external_storage, dir.path)))
|
|
||||||
.setOngoing(true)
|
|
||||||
|
|
||||||
} catch (e: IOException) {
|
|
||||||
log.log(Level.SEVERE, "Couldn't create external log file", e)
|
|
||||||
|
|
||||||
builder.setContentText(getString(R.string.logging_couldnt_create_file, e.localizedMessage))
|
|
||||||
.setCategory(NotificationCompat.CATEGORY_ERROR)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
builder.setContentText(getString(R.string.logging_no_external_storage))
|
|
||||||
|
|
||||||
nm.notify(Constants.NOTIFICATION_EXTERNAL_FILE_LOGGING, builder.build())
|
|
||||||
} else
|
|
||||||
nm.cancel(Constants.NOTIFICATION_EXTERNAL_FILE_LOGGING)
|
|
||||||
|
|
||||||
dbHelper.close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ReinitSettingsReceiver : BroadcastReceiver() {
|
class ReinitSettingsReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
log.info("Received broadcast: re-initializing settings (logger/cert manager)")
|
Logger.log.info("Received broadcast: re-initializing settings (logger/cert manager)")
|
||||||
|
|
||||||
val app = context.applicationContext as App
|
val app = context.applicationContext as App
|
||||||
app.reinitLogger()
|
app.reinitLogger()
|
||||||
@ -259,7 +190,7 @@ class App : Application() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun update(fromVersion: Int) {
|
private fun update(fromVersion: Int) {
|
||||||
App.log.info("Updating from version " + fromVersion + " to " + BuildConfig.VERSION_CODE)
|
Logger.log.info("Updating from version " + fromVersion + " to " + BuildConfig.VERSION_CODE)
|
||||||
|
|
||||||
if (fromVersion < 6) {
|
if (fromVersion < 6) {
|
||||||
val data = this.data
|
val data = this.data
|
||||||
@ -324,7 +255,7 @@ class App : Application() {
|
|||||||
|
|
||||||
@SuppressLint("UnsafeProtectedBroadcastReceiver,MissingPermission")
|
@SuppressLint("UnsafeProtectedBroadcastReceiver,MissingPermission")
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
App.log.info("EteSync was updated, checking for app version")
|
Logger.log.info("EteSync was updated, checking for app version")
|
||||||
|
|
||||||
val app = context.applicationContext as App
|
val app = context.applicationContext as App
|
||||||
val prefs = app.getSharedPreferences("app", Context.MODE_PRIVATE)
|
val prefs = app.getSharedPreferences("app", Context.MODE_PRIVATE)
|
||||||
@ -396,10 +327,8 @@ class App : Application() {
|
|||||||
var hostnameVerifier: HostnameVerifier? = null
|
var hostnameVerifier: HostnameVerifier? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
val log = Logger.getLogger("etesync")
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
at.bitfire.cert4android.Constants.log = Logger.getLogger("etesync.cert4android")
|
at.bitfire.cert4android.Constants.log = java.util.logging.Logger.getLogger("etesync.cert4android")
|
||||||
}
|
}
|
||||||
|
|
||||||
lateinit var accountType: String
|
lateinit var accountType: String
|
||||||
|
@ -24,7 +24,8 @@ import java.text.SimpleDateFormat
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger as LoggerType
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
|
|
||||||
object HttpClient {
|
object HttpClient {
|
||||||
private val client = OkHttpClient()
|
private val client = OkHttpClient()
|
||||||
@ -36,7 +37,7 @@ object HttpClient {
|
|||||||
userAgent = "${App.appName}/${BuildConfig.VERSION_NAME} (okhttp3) Android/${Build.VERSION.RELEASE}"
|
userAgent = "${App.appName}/${BuildConfig.VERSION_NAME} (okhttp3) Android/${Build.VERSION.RELEASE}"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun create(context: Context?, logger: Logger, host: String?, token: String): OkHttpClient {
|
fun create(context: Context?, logger: LoggerType, host: String?, token: String): OkHttpClient {
|
||||||
var builder = defaultBuilder(context, logger)
|
var builder = defaultBuilder(context, logger)
|
||||||
|
|
||||||
// use account settings for authentication
|
// use account settings for authentication
|
||||||
@ -46,21 +47,21 @@ object HttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun create(context: Context?, settings: AccountSettings, logger: Logger = App.log): OkHttpClient {
|
fun create(context: Context?, settings: AccountSettings, logger: LoggerType = Logger.log): OkHttpClient {
|
||||||
return create(context, logger, settings.uri!!.host, settings.authToken)
|
return create(context, logger, settings.uri!!.host, settings.authToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun create(context: Context?, logger: Logger = App.log): OkHttpClient {
|
fun create(context: Context?, logger: LoggerType = Logger.log): OkHttpClient {
|
||||||
return defaultBuilder(context, logger).build()
|
return defaultBuilder(context, logger).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun create(context: Context?, uri: URI, authToken: String): OkHttpClient {
|
fun create(context: Context?, uri: URI, authToken: String): OkHttpClient {
|
||||||
return create(context, App.log, uri.host, authToken)
|
return create(context, Logger.log, uri.host, authToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun defaultBuilder(context: Context?, logger: Logger): OkHttpClient.Builder {
|
private fun defaultBuilder(context: Context?, logger: LoggerType): OkHttpClient.Builder {
|
||||||
val builder = client.newBuilder()
|
val builder = client.newBuilder()
|
||||||
|
|
||||||
// use MemorizingTrustManager to manage self-signed certificates
|
// use MemorizingTrustManager to manage self-signed certificates
|
||||||
@ -90,12 +91,12 @@ object HttpClient {
|
|||||||
|
|
||||||
val proxy = Proxy(Proxy.Type.HTTP, address)
|
val proxy = Proxy(Proxy.Type.HTTP, address)
|
||||||
builder.proxy(proxy)
|
builder.proxy(proxy)
|
||||||
App.log.log(Level.INFO, "Using proxy", proxy)
|
Logger.log.log(Level.INFO, "Using proxy", proxy)
|
||||||
}
|
}
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
App.log.log(Level.SEVERE, "Can't set proxy, ignoring", e)
|
Logger.log.log(Level.SEVERE, "Can't set proxy, ignoring", e)
|
||||||
} catch (e: NullPointerException) {
|
} catch (e: NullPointerException) {
|
||||||
App.log.log(Level.SEVERE, "Can't set proxy, ignoring", e)
|
Logger.log.log(Level.SEVERE, "Can't set proxy, ignoring", e)
|
||||||
} finally {
|
} finally {
|
||||||
dbHelper.close()
|
dbHelper.close()
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import androidx.core.app.NotificationManagerCompat
|
|||||||
import at.bitfire.ical4android.CalendarStorageException
|
import at.bitfire.ical4android.CalendarStorageException
|
||||||
import at.bitfire.vcard4android.ContactsStorageException
|
import at.bitfire.vcard4android.ContactsStorageException
|
||||||
import com.etesync.syncadapter.journalmanager.Exceptions
|
import com.etesync.syncadapter.journalmanager.Exceptions
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.ui.AccountSettingsActivity
|
import com.etesync.syncadapter.ui.AccountSettingsActivity
|
||||||
import com.etesync.syncadapter.ui.DebugInfoActivity
|
import com.etesync.syncadapter.ui.DebugInfoActivity
|
||||||
import com.etesync.syncadapter.ui.WebViewActivity
|
import com.etesync.syncadapter.ui.WebViewActivity
|
||||||
@ -36,28 +37,28 @@ class NotificationHelper(internal val context: Context, internal val notificatio
|
|||||||
fun setThrowable(e: Throwable) {
|
fun setThrowable(e: Throwable) {
|
||||||
throwable = e
|
throwable = e
|
||||||
if (e is Exceptions.UnauthorizedException) {
|
if (e is Exceptions.UnauthorizedException) {
|
||||||
App.log.log(Level.SEVERE, "Not authorized anymore", e)
|
Logger.log.log(Level.SEVERE, "Not authorized anymore", e)
|
||||||
messageString = R.string.sync_error_unauthorized
|
messageString = R.string.sync_error_unauthorized
|
||||||
} else if (e is Exceptions.UserInactiveException) {
|
} else if (e is Exceptions.UserInactiveException) {
|
||||||
App.log.log(Level.SEVERE, "User inactive")
|
Logger.log.log(Level.SEVERE, "User inactive")
|
||||||
messageString = R.string.sync_error_user_inactive
|
messageString = R.string.sync_error_user_inactive
|
||||||
} else if (e is Exceptions.ServiceUnavailableException) {
|
} else if (e is Exceptions.ServiceUnavailableException) {
|
||||||
App.log.log(Level.SEVERE, "Service unavailable")
|
Logger.log.log(Level.SEVERE, "Service unavailable")
|
||||||
messageString = R.string.sync_error_unavailable
|
messageString = R.string.sync_error_unavailable
|
||||||
} else if (e is Exceptions.ReadOnlyException) {
|
} else if (e is Exceptions.ReadOnlyException) {
|
||||||
App.log.log(Level.SEVERE, "Journal is read only", e)
|
Logger.log.log(Level.SEVERE, "Journal is read only", e)
|
||||||
messageString = R.string.sync_error_journal_readonly
|
messageString = R.string.sync_error_journal_readonly
|
||||||
} else if (e is Exceptions.HttpException) {
|
} else if (e is Exceptions.HttpException) {
|
||||||
App.log.log(Level.SEVERE, "HTTP Exception during sync", e)
|
Logger.log.log(Level.SEVERE, "HTTP Exception during sync", e)
|
||||||
messageString = R.string.sync_error_http_dav
|
messageString = R.string.sync_error_http_dav
|
||||||
} else if (e is CalendarStorageException || e is ContactsStorageException || e is SQLiteException) {
|
} else if (e is CalendarStorageException || e is ContactsStorageException || e is SQLiteException) {
|
||||||
App.log.log(Level.SEVERE, "Couldn't access local storage", e)
|
Logger.log.log(Level.SEVERE, "Couldn't access local storage", e)
|
||||||
messageString = R.string.sync_error_local_storage
|
messageString = R.string.sync_error_local_storage
|
||||||
} else if (e is Exceptions.IntegrityException) {
|
} else if (e is Exceptions.IntegrityException) {
|
||||||
App.log.log(Level.SEVERE, "Integrity error", e)
|
Logger.log.log(Level.SEVERE, "Integrity error", e)
|
||||||
messageString = R.string.sync_error_integrity
|
messageString = R.string.sync_error_integrity
|
||||||
} else {
|
} else {
|
||||||
App.log.log(Level.SEVERE, "Unknown sync error", e)
|
Logger.log.log(Level.SEVERE, "Unknown sync error", e)
|
||||||
messageString = R.string.sync_error
|
messageString = R.string.sync_error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.provider.CalendarContract
|
import android.provider.CalendarContract
|
||||||
import at.bitfire.ical4android.TaskProvider
|
import at.bitfire.ical4android.TaskProvider
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.resource.LocalTaskList
|
import com.etesync.syncadapter.resource.LocalTaskList
|
||||||
|
|
||||||
class PackageChangedReceiver : BroadcastReceiver() {
|
class PackageChangedReceiver : BroadcastReceiver() {
|
||||||
@ -30,7 +31,7 @@ class PackageChangedReceiver : BroadcastReceiver() {
|
|||||||
|
|
||||||
internal fun updateTaskSync(context: Context) {
|
internal fun updateTaskSync(context: Context) {
|
||||||
val tasksInstalled = LocalTaskList.tasksProviderAvailable(context)
|
val tasksInstalled = LocalTaskList.tasksProviderAvailable(context)
|
||||||
App.log.info("Package (un)installed; OpenTasks provider now available = $tasksInstalled")
|
Logger.log.info("Package (un)installed; OpenTasks provider now available = $tasksInstalled")
|
||||||
|
|
||||||
for (account in AccountManager.get(context).getAccountsByType(App.accountType)) {
|
for (account in AccountManager.get(context).getAccountsByType(App.accountType)) {
|
||||||
val settings = AccountSettings(context, account)
|
val settings = AccountSettings(context, account)
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
package com.etesync.syncadapter
|
package com.etesync.syncadapter
|
||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.net.Socket
|
import java.net.Socket
|
||||||
@ -105,7 +106,7 @@ class SSLSocketFactoryCompat(trustManager: X509TrustManager) : SSLSocketFactory(
|
|||||||
// - all modern ciphers are activated by default
|
// - all modern ciphers are activated by default
|
||||||
protocols = null
|
protocols = null
|
||||||
cipherSuites = null
|
cipherSuites = null
|
||||||
App.log.fine("Using device default TLS protocols/ciphers")
|
Logger.log.fine("Using device default TLS protocols/ciphers")
|
||||||
} else {
|
} else {
|
||||||
(SSLSocketFactory.getDefault().createSocket() as? SSLSocket)?.use { socket ->
|
(SSLSocketFactory.getDefault().createSocket() as? SSLSocket)?.use { socket ->
|
||||||
try {
|
try {
|
||||||
@ -115,7 +116,7 @@ class SSLSocketFactoryCompat(trustManager: X509TrustManager) : SSLSocketFactory(
|
|||||||
val whichProtocols = LinkedList<String>()
|
val whichProtocols = LinkedList<String>()
|
||||||
for (protocol in socket.supportedProtocols.filterNot { it.contains("SSL", true) })
|
for (protocol in socket.supportedProtocols.filterNot { it.contains("SSL", true) })
|
||||||
whichProtocols += protocol
|
whichProtocols += protocol
|
||||||
App.log.info("Enabling (only) these TLS protocols: ${whichProtocols.joinToString(", ")}")
|
Logger.log.info("Enabling (only) these TLS protocols: ${whichProtocols.joinToString(", ")}")
|
||||||
protocols = whichProtocols.toTypedArray()
|
protocols = whichProtocols.toTypedArray()
|
||||||
|
|
||||||
/* set up reasonable cipher suites */
|
/* set up reasonable cipher suites */
|
||||||
@ -140,7 +141,7 @@ class SSLSocketFactoryCompat(trustManager: X509TrustManager) : SSLSocketFactory(
|
|||||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"
|
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"
|
||||||
)
|
)
|
||||||
val availableCiphers = socket.supportedCipherSuites
|
val availableCiphers = socket.supportedCipherSuites
|
||||||
App.log.info("Available cipher suites: ${availableCiphers.joinToString(", ")}")
|
Logger.log.info("Available cipher suites: ${availableCiphers.joinToString(", ")}")
|
||||||
|
|
||||||
/* For maximum security, preferredCiphers should *replace* enabled ciphers (thus
|
/* For maximum security, preferredCiphers should *replace* enabled ciphers (thus
|
||||||
* disabling ciphers which are enabled by default, but have become unsecure), but for
|
* disabling ciphers which are enabled by default, but have become unsecure), but for
|
||||||
@ -150,16 +151,16 @@ class SSLSocketFactoryCompat(trustManager: X509TrustManager) : SSLSocketFactory(
|
|||||||
// for the final set of enabled ciphers, take the ciphers enabled by default, ...
|
// for the final set of enabled ciphers, take the ciphers enabled by default, ...
|
||||||
val whichCiphers = LinkedList<String>()
|
val whichCiphers = LinkedList<String>()
|
||||||
whichCiphers.addAll(socket.enabledCipherSuites)
|
whichCiphers.addAll(socket.enabledCipherSuites)
|
||||||
App.log.fine("Cipher suites enabled by default: ${whichCiphers.joinToString(", ")}")
|
Logger.log.fine("Cipher suites enabled by default: ${whichCiphers.joinToString(", ")}")
|
||||||
// ... add explicitly allowed ciphers ...
|
// ... add explicitly allowed ciphers ...
|
||||||
whichCiphers.addAll(knownCiphers)
|
whichCiphers.addAll(knownCiphers)
|
||||||
// ... and keep only those which are actually available
|
// ... and keep only those which are actually available
|
||||||
whichCiphers.retainAll(availableCiphers)
|
whichCiphers.retainAll(availableCiphers)
|
||||||
|
|
||||||
App.log.info("Enabling (only) these TLS ciphers: " + whichCiphers.joinToString(", "))
|
Logger.log.info("Enabling (only) these TLS ciphers: " + whichCiphers.joinToString(", "))
|
||||||
cipherSuites = whichCiphers.toTypedArray()
|
cipherSuites = whichCiphers.toTypedArray()
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
App.log.severe("Couldn't determine default TLS settings")
|
Logger.log.severe("Couldn't determine default TLS settings")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.etesync.syncadapter.journalmanager
|
package com.etesync.syncadapter.journalmanager
|
||||||
|
|
||||||
import com.etesync.syncadapter.App
|
|
||||||
import com.etesync.syncadapter.GsonHelper
|
import com.etesync.syncadapter.GsonHelper
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import okhttp3.*
|
import okhttp3.*
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
@ -19,7 +19,7 @@ abstract class BaseManager {
|
|||||||
try {
|
try {
|
||||||
response = client!!.newCall(request).execute()
|
response = client!!.newCall(request).execute()
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
App.log.log(Level.SEVERE, "Failed while connecting to server", e)
|
Logger.log.log(Level.SEVERE, "Failed while connecting to server", e)
|
||||||
throw Exceptions.ServiceUnavailableException("[" + e.javaClass.name + "] " + e.localizedMessage)
|
throw Exceptions.ServiceUnavailableException("[" + e.javaClass.name + "] " + e.localizedMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.etesync.syncadapter.journalmanager
|
package com.etesync.syncadapter.journalmanager
|
||||||
|
|
||||||
import com.etesync.syncadapter.App
|
|
||||||
import com.etesync.syncadapter.journalmanager.util.ByteUtil
|
import com.etesync.syncadapter.journalmanager.util.ByteUtil
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.utils.Base64
|
import com.etesync.syncadapter.utils.Base64
|
||||||
import org.apache.commons.lang3.ArrayUtils
|
import org.apache.commons.lang3.ArrayUtils
|
||||||
import org.spongycastle.crypto.AsymmetricBlockCipher
|
import org.spongycastle.crypto.AsymmetricBlockCipher
|
||||||
@ -69,7 +69,7 @@ object Crypto {
|
|||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
} catch (e: InvalidCipherTextException) {
|
} catch (e: InvalidCipherTextException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
App.log.severe("Invalid ciphertext: " + Base64.encodeToString(content, Base64.NO_WRAP))
|
Logger.log.severe("Invalid ciphertext: " + Base64.encodeToString(content, Base64.NO_WRAP))
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
@ -85,7 +85,7 @@ object Crypto {
|
|||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
} catch (e: InvalidCipherTextException) {
|
} catch (e: InvalidCipherTextException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
App.log.severe("Invalid ciphertext: " + Base64.encodeToString(cipherText, Base64.NO_WRAP))
|
Logger.log.severe("Invalid ciphertext: " + Base64.encodeToString(cipherText, Base64.NO_WRAP))
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
@ -182,7 +182,7 @@ object Crypto {
|
|||||||
len += cipher.doFinal(buf, len)
|
len += cipher.doFinal(buf, len)
|
||||||
} catch (e: InvalidCipherTextException) {
|
} catch (e: InvalidCipherTextException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
App.log.severe("Invalid ciphertext: " + Base64.encodeToString(_data, Base64.NO_WRAP))
|
Logger.log.severe("Invalid ciphertext: " + Base64.encodeToString(_data, Base64.NO_WRAP))
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +205,7 @@ object Crypto {
|
|||||||
try {
|
try {
|
||||||
cipher.doFinal(buf, len)
|
cipher.doFinal(buf, len)
|
||||||
} catch (e: InvalidCipherTextException) {
|
} catch (e: InvalidCipherTextException) {
|
||||||
App.log.severe("Invalid ciphertext: " + Base64.encodeToString(data, Base64.NO_WRAP))
|
Logger.log.severe("Invalid ciphertext: " + Base64.encodeToString(data, Base64.NO_WRAP))
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.etesync.syncadapter.journalmanager
|
package com.etesync.syncadapter.journalmanager
|
||||||
|
|
||||||
import com.etesync.syncadapter.App
|
|
||||||
import com.etesync.syncadapter.GsonHelper
|
import com.etesync.syncadapter.GsonHelper
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
@ -17,7 +17,7 @@ class JournalEntryManager(httpClient: OkHttpClient, remote: HttpUrl, val uid: St
|
|||||||
.addPathSegment("entries")
|
.addPathSegment("entries")
|
||||||
.addPathSegment("")
|
.addPathSegment("")
|
||||||
.build()
|
.build()
|
||||||
App.log.info("Created for: " + this.remote!!.toString())
|
Logger.log.info("Created for: " + this.remote!!.toString())
|
||||||
|
|
||||||
this.client = httpClient
|
this.client = httpClient
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package com.etesync.syncadapter.journalmanager
|
package com.etesync.syncadapter.journalmanager
|
||||||
|
|
||||||
import com.etesync.syncadapter.App
|
|
||||||
import com.etesync.syncadapter.GsonHelper
|
import com.etesync.syncadapter.GsonHelper
|
||||||
import com.etesync.syncadapter.journalmanager.Crypto.CryptoManager.Companion.HMAC_SIZE
|
import com.etesync.syncadapter.journalmanager.Crypto.CryptoManager.Companion.HMAC_SIZE
|
||||||
import com.etesync.syncadapter.journalmanager.Crypto.sha256
|
import com.etesync.syncadapter.journalmanager.Crypto.sha256
|
||||||
import com.etesync.syncadapter.journalmanager.Crypto.toHex
|
import com.etesync.syncadapter.journalmanager.Crypto.toHex
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
@ -19,7 +19,7 @@ class JournalManager(httpClient: OkHttpClient, remote: HttpUrl) : BaseManager()
|
|||||||
.addPathSegments("api/v1/journals")
|
.addPathSegments("api/v1/journals")
|
||||||
.addPathSegment("")
|
.addPathSegment("")
|
||||||
.build()
|
.build()
|
||||||
App.log.info("Created for: " + this.remote!!.toString())
|
Logger.log.info("Created for: " + this.remote!!.toString())
|
||||||
|
|
||||||
this.client = httpClient
|
this.client = httpClient
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ object Logger : SharedPreferences.OnSharedPreferenceChangeListener {
|
|||||||
val settings = Settings(dbHelper.readableDatabase)
|
val settings = Settings(dbHelper.readableDatabase)
|
||||||
|
|
||||||
val logToFile = settings.getBoolean(App.LOG_TO_EXTERNAL_STORAGE, false)
|
val logToFile = settings.getBoolean(App.LOG_TO_EXTERNAL_STORAGE, false)
|
||||||
val logVerbose = logToFile || Log.isLoggable(App.log.name, Log.DEBUG)
|
val logVerbose = logToFile || Log.isLoggable(Logger.log.name, Log.DEBUG)
|
||||||
|
|
||||||
log.info("Verbose logging: $logVerbose; to file: $logToFile")
|
log.info("Verbose logging: $logVerbose; to file: $logToFile")
|
||||||
|
|
||||||
|
@ -14,9 +14,8 @@ import android.database.sqlite.SQLiteDatabase;
|
|||||||
import android.database.sqlite.SQLiteException;
|
import android.database.sqlite.SQLiteException;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
|
|
||||||
import com.etesync.syncadapter.App;
|
import androidx.annotation.RequiresApi;
|
||||||
|
|
||||||
public class ServiceDB {
|
public class ServiceDB {
|
||||||
|
|
||||||
@ -75,8 +74,6 @@ public class ServiceDB {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(SQLiteDatabase db) {
|
public void onCreate(SQLiteDatabase db) {
|
||||||
App.Companion.getLog().info("Creating database " + db.getPath());
|
|
||||||
|
|
||||||
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" +
|
||||||
|
@ -20,6 +20,7 @@ import android.provider.ContactsContract.Groups
|
|||||||
import android.provider.ContactsContract.RawContacts
|
import android.provider.ContactsContract.RawContacts
|
||||||
import at.bitfire.vcard4android.*
|
import at.bitfire.vcard4android.*
|
||||||
import com.etesync.syncadapter.App
|
import com.etesync.syncadapter.App
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
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 java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
@ -156,13 +157,13 @@ class LocalAddressBook(
|
|||||||
arrayOf(account.name, account.type))
|
arrayOf(account.name, account.type))
|
||||||
}
|
}
|
||||||
} catch (e: RemoteException) {
|
} catch (e: RemoteException) {
|
||||||
App.log.log(Level.WARNING, "Couldn't re-assign contacts to new account name", e)
|
Logger.log.log(Level.WARNING, "Couldn't re-assign contacts to new account name", e)
|
||||||
}
|
}
|
||||||
}, null)
|
}, null)
|
||||||
account = future.result
|
account = future.result
|
||||||
}
|
}
|
||||||
|
|
||||||
App.log.info("Address book write permission? = ${!journalEntity.isReadOnly}")
|
Logger.log.info("Address book write permission? = ${!journalEntity.isReadOnly}")
|
||||||
readOnly = journalEntity.isReadOnly
|
readOnly = journalEntity.isReadOnly
|
||||||
|
|
||||||
// make sure it will still be synchronized when contacts are updated
|
// make sure it will still be synchronized when contacts are updated
|
||||||
@ -244,10 +245,10 @@ class LocalAddressBook(
|
|||||||
val currentHash = contact.dataHashCode()
|
val currentHash = contact.dataHashCode()
|
||||||
if (lastHash == currentHash) {
|
if (lastHash == currentHash) {
|
||||||
// hash is code still the same, contact is not "really dirty" (only metadata been have changed)
|
// hash is code still the same, contact is not "really dirty" (only metadata been have changed)
|
||||||
App.log.log(Level.FINE, "Contact data hash has not changed, resetting dirty flag", contact)
|
Logger.log.log(Level.FINE, "Contact data hash has not changed, resetting dirty flag", contact)
|
||||||
contact.resetDirty()
|
contact.resetDirty()
|
||||||
} else {
|
} else {
|
||||||
App.log.log(Level.FINE, "Contact data has changed from hash $lastHash to $currentHash", contact)
|
Logger.log.log(Level.FINE, "Contact data has changed from hash $lastHash to $currentHash", contact)
|
||||||
reallyDirty++
|
reallyDirty++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -338,7 +339,7 @@ class LocalAddressBook(
|
|||||||
// find groups without members
|
// find groups without members
|
||||||
/** should be done using {@link Groups.SUMMARY_COUNT}, but it's not implemented in Android yet */
|
/** should be done using {@link Groups.SUMMARY_COUNT}, but it's not implemented in Android yet */
|
||||||
queryGroups(null, null).filter { it.getMembers().isEmpty() }.forEach { group ->
|
queryGroups(null, null).filter { it.getMembers().isEmpty() }.forEach { group ->
|
||||||
App.log.log(Level.FINE, "Deleting group", group)
|
Logger.log.log(Level.FINE, "Deleting group", group)
|
||||||
group.delete()
|
group.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -355,7 +356,7 @@ class LocalAddressBook(
|
|||||||
try {
|
try {
|
||||||
val fixed = provider?.update(syncAdapterURI(RawContacts.CONTENT_URI),
|
val fixed = provider?.update(syncAdapterURI(RawContacts.CONTENT_URI),
|
||||||
values, where, null)
|
values, where, null)
|
||||||
App.log.info("Fixed entries: " + fixed.toString())
|
Logger.log.info("Fixed entries: " + fixed.toString())
|
||||||
} catch (e: RemoteException) {
|
} catch (e: RemoteException) {
|
||||||
throw ContactsStorageException("Couldn't query contacts", e)
|
throw ContactsStorageException("Couldn't query contacts", e)
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ import android.os.RemoteException
|
|||||||
import android.provider.CalendarContract
|
import android.provider.CalendarContract
|
||||||
import android.provider.CalendarContract.*
|
import android.provider.CalendarContract.*
|
||||||
import at.bitfire.ical4android.*
|
import at.bitfire.ical4android.*
|
||||||
import com.etesync.syncadapter.App
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.model.JournalEntity
|
import com.etesync.syncadapter.model.JournalEntity
|
||||||
import org.apache.commons.lang3.StringUtils
|
import org.apache.commons.lang3.StringUtils
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -77,7 +77,7 @@ class LocalCalendar private constructor(
|
|||||||
values.put(Calendars.CALENDAR_TIME_ZONE, DateUtils.findAndroidTimezoneID(tzId.value))
|
values.put(Calendars.CALENDAR_TIME_ZONE, DateUtils.findAndroidTimezoneID(tzId.value))
|
||||||
}
|
}
|
||||||
} catch(e: IllegalArgumentException) {
|
} catch(e: IllegalArgumentException) {
|
||||||
App.log.log(Level.WARNING, "Couldn't parse calendar default time zone", e)
|
Logger.log.log(Level.WARNING, "Couldn't parse calendar default time zone", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
values.put(Calendars.ALLOWED_REMINDERS, Reminders.METHOD_ALERT)
|
values.put(Calendars.ALLOWED_REMINDERS, Reminders.METHOD_ALERT)
|
||||||
@ -125,14 +125,14 @@ class LocalCalendar private constructor(
|
|||||||
|
|
||||||
fun processDirtyExceptions() {
|
fun processDirtyExceptions() {
|
||||||
// process deleted exceptions
|
// process deleted exceptions
|
||||||
App.log.info("Processing deleted exceptions")
|
Logger.log.info("Processing deleted exceptions")
|
||||||
try {
|
try {
|
||||||
val cursor = provider.query(
|
val cursor = provider.query(
|
||||||
syncAdapterURI(Events.CONTENT_URI),
|
syncAdapterURI(Events.CONTENT_URI),
|
||||||
arrayOf(Events._ID, Events.ORIGINAL_ID, LocalEvent.COLUMN_SEQUENCE),
|
arrayOf(Events._ID, Events.ORIGINAL_ID, LocalEvent.COLUMN_SEQUENCE),
|
||||||
Events.DELETED + "!=0 AND " + Events.ORIGINAL_ID + " IS NOT NULL", null, null)
|
Events.DELETED + "!=0 AND " + Events.ORIGINAL_ID + " IS NOT NULL", null, null)
|
||||||
while (cursor != null && cursor.moveToNext()) {
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
App.log.fine("Found deleted exception, removing; then re-schuling original event")
|
Logger.log.fine("Found deleted exception, removing; then re-schuling original event")
|
||||||
val id = cursor.getLong(0)
|
val id = cursor.getLong(0)
|
||||||
// can't be null (by definition)
|
// can't be null (by definition)
|
||||||
val originalID = cursor.getLong(1) // can't be null (by query)
|
val originalID = cursor.getLong(1) // can't be null (by query)
|
||||||
@ -163,14 +163,14 @@ class LocalCalendar private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// process dirty exceptions
|
// process dirty exceptions
|
||||||
App.log.info("Processing dirty exceptions")
|
Logger.log.info("Processing dirty exceptions")
|
||||||
try {
|
try {
|
||||||
val cursor = provider.query(
|
val cursor = provider.query(
|
||||||
syncAdapterURI(Events.CONTENT_URI),
|
syncAdapterURI(Events.CONTENT_URI),
|
||||||
arrayOf(Events._ID, Events.ORIGINAL_ID, LocalEvent.COLUMN_SEQUENCE),
|
arrayOf(Events._ID, Events.ORIGINAL_ID, LocalEvent.COLUMN_SEQUENCE),
|
||||||
Events.DIRTY + "!=0 AND " + Events.ORIGINAL_ID + " IS NOT NULL", null, null)
|
Events.DIRTY + "!=0 AND " + Events.ORIGINAL_ID + " IS NOT NULL", null, null)
|
||||||
while (cursor != null && cursor.moveToNext()) {
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
App.log.fine("Found dirty exception, increasing SEQUENCE to re-schedule")
|
Logger.log.fine("Found dirty exception, increasing SEQUENCE to re-schedule")
|
||||||
val id = cursor.getLong(0)
|
val id = cursor.getLong(0)
|
||||||
// can't be null (by definition)
|
// can't be null (by definition)
|
||||||
val originalID = cursor.getLong(1) // can't be null (by query)
|
val originalID = cursor.getLong(1) // can't be null (by query)
|
||||||
@ -227,7 +227,7 @@ class LocalCalendar private constructor(
|
|||||||
try {
|
try {
|
||||||
val fixed = provider.update(syncAdapterURI(Events.CONTENT_URI),
|
val fixed = provider.update(syncAdapterURI(Events.CONTENT_URI),
|
||||||
values, where, whereArgs)
|
values, where, whereArgs)
|
||||||
App.log.info("Fixed entries: " + fixed.toString())
|
Logger.log.info("Fixed entries: " + fixed.toString())
|
||||||
} catch (e: RemoteException) {
|
} catch (e: RemoteException) {
|
||||||
throw CalendarStorageException("Couldn't fix etags", e)
|
throw CalendarStorageException("Couldn't fix etags", e)
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,8 @@ import at.bitfire.vcard4android.CachedGroupMembership
|
|||||||
import at.bitfire.vcard4android.Contact
|
import at.bitfire.vcard4android.Contact
|
||||||
import at.bitfire.vcard4android.ContactsStorageException
|
import at.bitfire.vcard4android.ContactsStorageException
|
||||||
import at.bitfire.vcard4android.GroupMethod.GROUP_VCARDS
|
import at.bitfire.vcard4android.GroupMethod.GROUP_VCARDS
|
||||||
import com.etesync.syncadapter.App
|
|
||||||
import com.etesync.syncadapter.Constants
|
import com.etesync.syncadapter.Constants
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.model.UnknownProperties
|
import com.etesync.syncadapter.model.UnknownProperties
|
||||||
import ezvcard.Ezvcard
|
import ezvcard.Ezvcard
|
||||||
import ezvcard.VCardVersion
|
import ezvcard.VCardVersion
|
||||||
@ -62,7 +62,7 @@ class LocalContact : AndroidContact, LocalAddress {
|
|||||||
val contact: Contact
|
val contact: Contact
|
||||||
contact = this.contact!!
|
contact = this.contact!!
|
||||||
|
|
||||||
App.log.log(Level.FINE, "Preparing upload of VCard $uuid", contact)
|
Logger.log.log(Level.FINE, "Preparing upload of VCard $uuid", contact)
|
||||||
|
|
||||||
val os = ByteArrayOutputStream()
|
val os = ByteArrayOutputStream()
|
||||||
contact.write(VCardVersion.V4_0, GROUP_VCARDS, os)
|
contact.write(VCardVersion.V4_0, GROUP_VCARDS, os)
|
||||||
@ -97,7 +97,7 @@ class LocalContact : AndroidContact, LocalAddress {
|
|||||||
// workaround for Android 7 which sets DIRTY flag when only meta-data is changed
|
// workaround for Android 7 which sets DIRTY flag when only meta-data is changed
|
||||||
val hashCode = dataHashCode()
|
val hashCode = dataHashCode()
|
||||||
values.put(COLUMN_HASHCODE, hashCode)
|
values.put(COLUMN_HASHCODE, hashCode)
|
||||||
App.log.finer("Clearing dirty flag with eTag = $eTag, contact hash = $hashCode")
|
Logger.log.finer("Clearing dirty flag with eTag = $eTag, contact hash = $hashCode")
|
||||||
}
|
}
|
||||||
|
|
||||||
addressBook.provider?.update(rawContactSyncURI(), values, null, null)
|
addressBook.provider?.update(rawContactSyncURI(), values, null, null)
|
||||||
@ -173,7 +173,7 @@ class LocalContact : AndroidContact, LocalAddress {
|
|||||||
// groupMemberships is filled by getContact()
|
// groupMemberships is filled by getContact()
|
||||||
val dataHash = contact!!.hashCode()
|
val dataHash = contact!!.hashCode()
|
||||||
val groupHash = groupMemberships.hashCode()
|
val groupHash = groupMemberships.hashCode()
|
||||||
App.log.finest("Calculated data hash = $dataHash, group memberships hash = $groupHash")
|
Logger.log.finest("Calculated data hash = $dataHash, group memberships hash = $groupHash")
|
||||||
return dataHash xor groupHash
|
return dataHash xor groupHash
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +183,7 @@ class LocalContact : AndroidContact, LocalAddress {
|
|||||||
|
|
||||||
val values = ContentValues(1)
|
val values = ContentValues(1)
|
||||||
val hashCode = dataHashCode()
|
val hashCode = dataHashCode()
|
||||||
App.log.fine("Storing contact hash = $hashCode")
|
Logger.log.fine("Storing contact hash = $hashCode")
|
||||||
values.put(COLUMN_HASHCODE, hashCode)
|
values.put(COLUMN_HASHCODE, hashCode)
|
||||||
|
|
||||||
if (batch == null)
|
if (batch == null)
|
||||||
|
@ -16,8 +16,8 @@ import android.provider.CalendarContract.Events
|
|||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import at.bitfire.ical4android.*
|
import at.bitfire.ical4android.*
|
||||||
import at.bitfire.ical4android.Constants.ical4jVersion
|
import at.bitfire.ical4android.Constants.ical4jVersion
|
||||||
import com.etesync.syncadapter.App
|
|
||||||
import com.etesync.syncadapter.Constants
|
import com.etesync.syncadapter.Constants
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import net.fortuna.ical4j.model.property.ProdId
|
import net.fortuna.ical4j.model.property.ProdId
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -43,7 +43,7 @@ class LocalEvent : AndroidEvent, LocalResource<Event> {
|
|||||||
|
|
||||||
override val content: String
|
override val content: String
|
||||||
get() {
|
get() {
|
||||||
App.log.log(Level.FINE, "Preparing upload of event " + fileName!!, event)
|
Logger.log.log(Level.FINE, "Preparing upload of event " + fileName!!, event)
|
||||||
|
|
||||||
val os = ByteArrayOutputStream()
|
val os = ByteArrayOutputStream()
|
||||||
event?.write(os)
|
event?.write(os)
|
||||||
|
@ -21,7 +21,7 @@ import android.provider.ContactsContract.RawContacts.Data
|
|||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import at.bitfire.vcard4android.*
|
import at.bitfire.vcard4android.*
|
||||||
import at.bitfire.vcard4android.GroupMethod.GROUP_VCARDS
|
import at.bitfire.vcard4android.GroupMethod.GROUP_VCARDS
|
||||||
import com.etesync.syncadapter.App
|
import com.etesync.syncadapter.log.Logger
|
||||||
import ezvcard.VCardVersion
|
import ezvcard.VCardVersion
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -86,7 +86,7 @@ class LocalGroup : AndroidGroup, LocalAddress {
|
|||||||
val contact: Contact
|
val contact: Contact
|
||||||
contact = this.contact!!
|
contact = this.contact!!
|
||||||
|
|
||||||
App.log.log(Level.FINE, "Preparing upload of VCard $uuid", contact)
|
Logger.log.log(Level.FINE, "Preparing upload of VCard $uuid", contact)
|
||||||
|
|
||||||
val os = ByteArrayOutputStream()
|
val os = ByteArrayOutputStream()
|
||||||
contact.write(VCardVersion.V4_0, GROUP_VCARDS, os)
|
contact.write(VCardVersion.V4_0, GROUP_VCARDS, os)
|
||||||
|
@ -15,7 +15,7 @@ import at.bitfire.ical4android.AndroidTask
|
|||||||
import at.bitfire.ical4android.AndroidTaskFactory
|
import at.bitfire.ical4android.AndroidTaskFactory
|
||||||
import at.bitfire.ical4android.AndroidTaskList
|
import at.bitfire.ical4android.AndroidTaskList
|
||||||
import at.bitfire.ical4android.Task
|
import at.bitfire.ical4android.Task
|
||||||
import com.etesync.syncadapter.App
|
import com.etesync.syncadapter.log.Logger
|
||||||
import org.dmfs.tasks.contract.TaskContract
|
import org.dmfs.tasks.contract.TaskContract
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -33,7 +33,7 @@ class LocalTask : AndroidTask, LocalResource<Task> {
|
|||||||
|
|
||||||
override val content: String
|
override val content: String
|
||||||
get() {
|
get() {
|
||||||
App.log.log(Level.FINE, "Preparing upload of task ${fileName} ${task}")
|
Logger.log.log(Level.FINE, "Preparing upload of task ${fileName} ${task}")
|
||||||
|
|
||||||
val os = ByteArrayOutputStream()
|
val os = ByteArrayOutputStream()
|
||||||
task?.write(os)
|
task?.write(os)
|
||||||
|
@ -19,6 +19,7 @@ import at.bitfire.vcard4android.ContactsStorageException
|
|||||||
import com.etesync.syncadapter.*
|
import com.etesync.syncadapter.*
|
||||||
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
||||||
import com.etesync.syncadapter.journalmanager.Exceptions
|
import com.etesync.syncadapter.journalmanager.Exceptions
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
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.JournalModel
|
||||||
@ -46,7 +47,7 @@ class AddressBooksSyncAdapterService : SyncAdapterService() {
|
|||||||
try {
|
try {
|
||||||
val contactsProvider = context.contentResolver.acquireContentProviderClient(ContactsContract.AUTHORITY)
|
val contactsProvider = context.contentResolver.acquireContentProviderClient(ContactsContract.AUTHORITY)
|
||||||
if (contactsProvider == null) {
|
if (contactsProvider == null) {
|
||||||
App.log.severe("Couldn't access contacts provider")
|
Logger.log.severe("Couldn't access contacts provider")
|
||||||
syncResult.databaseError = true
|
syncResult.databaseError = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -63,7 +64,7 @@ class AddressBooksSyncAdapterService : SyncAdapterService() {
|
|||||||
|
|
||||||
val accountManager = AccountManager.get(context)
|
val accountManager = AccountManager.get(context)
|
||||||
for (addressBookAccount in accountManager.getAccountsByType(App.addressBookAccountType)) {
|
for (addressBookAccount in accountManager.getAccountsByType(App.addressBookAccountType)) {
|
||||||
App.log.log(Level.INFO, "Running sync for address book", addressBookAccount)
|
Logger.log.log(Level.INFO, "Running sync for address book", addressBookAccount)
|
||||||
val syncExtras = Bundle(extras)
|
val syncExtras = Bundle(extras)
|
||||||
syncExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true)
|
syncExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true)
|
||||||
syncExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true)
|
syncExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true)
|
||||||
@ -76,7 +77,7 @@ class AddressBooksSyncAdapterService : SyncAdapterService() {
|
|||||||
// Ignore
|
// Ignore
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
if (e is ContactsStorageException || e is SQLiteException) {
|
if (e is ContactsStorageException || e is SQLiteException) {
|
||||||
App.log.log(Level.SEVERE, "Couldn't prepare local address books", e)
|
Logger.log.log(Level.SEVERE, "Couldn't prepare local address books", e)
|
||||||
syncResult.databaseError = true
|
syncResult.databaseError = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +103,7 @@ class AddressBooksSyncAdapterService : SyncAdapterService() {
|
|||||||
notificationManager.notify(title, context.getString(syncPhase))
|
notificationManager.notify(title, context.getString(syncPhase))
|
||||||
}
|
}
|
||||||
|
|
||||||
App.log.info("Address book sync complete")
|
Logger.log.info("Address book sync complete")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -125,11 +126,11 @@ class AddressBooksSyncAdapterService : SyncAdapterService() {
|
|||||||
val url = addressBook.url
|
val url = addressBook.url
|
||||||
val journalEntity = remote[url]
|
val journalEntity = remote[url]
|
||||||
if (journalEntity == null) {
|
if (journalEntity == null) {
|
||||||
App.log.fine("Deleting obsolete local address book $url")
|
Logger.log.fine("Deleting obsolete local address book $url")
|
||||||
addressBook.delete()
|
addressBook.delete()
|
||||||
} else {
|
} else {
|
||||||
// remote CollectionInfo found for this local collection, update data
|
// remote CollectionInfo found for this local collection, update data
|
||||||
App.log.fine("Updating local address book $url with $journalEntity")
|
Logger.log.fine("Updating local address book $url with $journalEntity")
|
||||||
addressBook.update(journalEntity)
|
addressBook.update(journalEntity)
|
||||||
// we already have a local collection for this remote collection, don't take into consideration anymore
|
// we already have a local collection for this remote collection, don't take into consideration anymore
|
||||||
remote.remove(url)
|
remote.remove(url)
|
||||||
@ -139,7 +140,7 @@ class AddressBooksSyncAdapterService : SyncAdapterService() {
|
|||||||
// create new local address books
|
// create new local address books
|
||||||
for (url in remote.keys) {
|
for (url in remote.keys) {
|
||||||
val journalEntity = remote[url]!!
|
val journalEntity = remote[url]!!
|
||||||
App.log.info("Adding local address book $journalEntity")
|
Logger.log.info("Adding local address book $journalEntity")
|
||||||
LocalAddressBook.create(context, provider, account, journalEntity)
|
LocalAddressBook.create(context, provider, account, journalEntity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,13 @@ import at.bitfire.ical4android.CalendarStorageException
|
|||||||
import at.bitfire.ical4android.Event
|
import at.bitfire.ical4android.Event
|
||||||
import at.bitfire.ical4android.InvalidCalendarException
|
import at.bitfire.ical4android.InvalidCalendarException
|
||||||
import at.bitfire.vcard4android.ContactsStorageException
|
import at.bitfire.vcard4android.ContactsStorageException
|
||||||
import com.etesync.syncadapter.*
|
import com.etesync.syncadapter.AccountSettings
|
||||||
|
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.journalmanager.Exceptions
|
||||||
import com.etesync.syncadapter.journalmanager.JournalEntryManager
|
import com.etesync.syncadapter.journalmanager.JournalEntryManager
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.model.CollectionInfo
|
import com.etesync.syncadapter.model.CollectionInfo
|
||||||
import com.etesync.syncadapter.model.SyncEntry
|
import com.etesync.syncadapter.model.SyncEntry
|
||||||
import com.etesync.syncadapter.resource.LocalCalendar
|
import com.etesync.syncadapter.resource.LocalCalendar
|
||||||
@ -80,10 +84,10 @@ constructor(context: Context, account: Account, settings: AccountSettings, extra
|
|||||||
|
|
||||||
val events = Event.fromReader(inputReader)
|
val events = Event.fromReader(inputReader)
|
||||||
if (events.size == 0) {
|
if (events.size == 0) {
|
||||||
App.log.warning("Received VCard without data, ignoring")
|
Logger.log.warning("Received VCard without data, ignoring")
|
||||||
return
|
return
|
||||||
} else if (events.size > 1) {
|
} else if (events.size > 1) {
|
||||||
App.log.warning("Received multiple VCALs, using first one")
|
Logger.log.warning("Received multiple VCALs, using first one")
|
||||||
}
|
}
|
||||||
|
|
||||||
val event = events[0]
|
val event = events[0]
|
||||||
@ -93,10 +97,10 @@ constructor(context: Context, account: Account, settings: AccountSettings, extra
|
|||||||
processEvent(event, local)
|
processEvent(event, local)
|
||||||
} else {
|
} else {
|
||||||
if (local != null) {
|
if (local != null) {
|
||||||
App.log.info("Removing local record #" + local.id + " which has been deleted on the server")
|
Logger.log.info("Removing local record #" + local.id + " which has been deleted on the server")
|
||||||
local.delete()
|
local.delete()
|
||||||
} else {
|
} else {
|
||||||
App.log.warning("Tried deleting a non-existent record: " + event.uid)
|
Logger.log.warning("Tried deleting a non-existent record: " + event.uid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,12 +144,12 @@ constructor(context: Context, account: Account, settings: AccountSettings, extra
|
|||||||
var localEvent = _localEvent
|
var localEvent = _localEvent
|
||||||
// delete local event, if it exists
|
// delete local event, if it exists
|
||||||
if (localEvent != null) {
|
if (localEvent != null) {
|
||||||
App.log.info("Updating " + newData.uid + " in local calendar")
|
Logger.log.info("Updating " + newData.uid + " in local calendar")
|
||||||
localEvent.eTag = newData.uid
|
localEvent.eTag = newData.uid
|
||||||
localEvent.update(newData)
|
localEvent.update(newData)
|
||||||
syncResult.stats.numUpdates++
|
syncResult.stats.numUpdates++
|
||||||
} else {
|
} else {
|
||||||
App.log.info("Adding " + newData.uid + " to local calendar")
|
Logger.log.info("Adding " + newData.uid + " to local calendar")
|
||||||
localEvent = LocalEvent(localCalendar(), newData, newData.uid, newData.uid)
|
localEvent = LocalEvent(localCalendar(), newData, newData.uid, newData.uid)
|
||||||
localEvent.add()
|
localEvent.add()
|
||||||
syncResult.stats.numInserts++
|
syncResult.stats.numInserts++
|
||||||
|
@ -17,6 +17,7 @@ import at.bitfire.ical4android.CalendarStorageException
|
|||||||
import com.etesync.syncadapter.*
|
import com.etesync.syncadapter.*
|
||||||
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
||||||
import com.etesync.syncadapter.journalmanager.Exceptions
|
import com.etesync.syncadapter.journalmanager.Exceptions
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
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.JournalModel
|
||||||
@ -53,7 +54,7 @@ class CalendarsSyncAdapterService : SyncAdapterService() {
|
|||||||
val principal = HttpUrl.get(settings.uri!!)!!
|
val principal = HttpUrl.get(settings.uri!!)!!
|
||||||
|
|
||||||
for (calendar in AndroidCalendar.find(account, provider, LocalCalendar.Factory, CalendarContract.Calendars.SYNC_EVENTS + "!=0", null)) {
|
for (calendar in AndroidCalendar.find(account, provider, LocalCalendar.Factory, CalendarContract.Calendars.SYNC_EVENTS + "!=0", null)) {
|
||||||
App.log.info("Synchronizing calendar #" + calendar.id + ", URL: " + calendar.name)
|
Logger.log.info("Synchronizing calendar #" + calendar.id + ", URL: " + calendar.name)
|
||||||
val syncManager = CalendarSyncManager(context, account, settings, extras, authority, syncResult, calendar, principal)
|
val syncManager = CalendarSyncManager(context, account, settings, extras, authority, syncResult, calendar, principal)
|
||||||
syncManager.performSync()
|
syncManager.performSync()
|
||||||
}
|
}
|
||||||
@ -64,7 +65,7 @@ class CalendarsSyncAdapterService : SyncAdapterService() {
|
|||||||
// Ignore
|
// Ignore
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
if (e is CalendarStorageException || e is SQLiteException) {
|
if (e is CalendarStorageException || e is SQLiteException) {
|
||||||
App.log.log(Level.SEVERE, "Couldn't prepare local calendars", e)
|
Logger.log.log(Level.SEVERE, "Couldn't prepare local calendars", e)
|
||||||
syncResult.databaseError = true
|
syncResult.databaseError = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +91,7 @@ class CalendarsSyncAdapterService : SyncAdapterService() {
|
|||||||
notificationManager.notify(title, context.getString(syncPhase))
|
notificationManager.notify(title, context.getString(syncPhase))
|
||||||
}
|
}
|
||||||
|
|
||||||
App.log.info("Calendar sync complete")
|
Logger.log.info("Calendar sync complete")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(CalendarStorageException::class)
|
@Throws(CalendarStorageException::class)
|
||||||
@ -113,11 +114,11 @@ class CalendarsSyncAdapterService : SyncAdapterService() {
|
|||||||
val url = calendar.name
|
val url = calendar.name
|
||||||
val journalEntity = remote[url]
|
val journalEntity = remote[url]
|
||||||
if (journalEntity == null) {
|
if (journalEntity == null) {
|
||||||
App.log.fine("Deleting obsolete local calendar $url")
|
Logger.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
|
||||||
App.log.fine("Updating local calendar $url with $journalEntity")
|
Logger.log.fine("Updating local calendar $url with $journalEntity")
|
||||||
calendar.update(journalEntity, updateColors)
|
calendar.update(journalEntity, updateColors)
|
||||||
// we already have a local calendar for this remote collection, don't take into consideration anymore
|
// we already have a local calendar for this remote collection, don't take into consideration anymore
|
||||||
remote.remove(url)
|
remote.remove(url)
|
||||||
@ -127,7 +128,7 @@ class CalendarsSyncAdapterService : SyncAdapterService() {
|
|||||||
// create new local calendars
|
// create new local calendars
|
||||||
for (url in remote.keys) {
|
for (url in remote.keys) {
|
||||||
val journalEntity = remote[url]!!
|
val journalEntity = remote[url]!!
|
||||||
App.log.info("Adding local calendar list $journalEntity")
|
Logger.log.info("Adding local calendar list $journalEntity")
|
||||||
LocalCalendar.create(account, provider, journalEntity)
|
LocalCalendar.create(account, provider, journalEntity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import at.bitfire.vcard4android.ContactsStorageException
|
|||||||
import com.etesync.syncadapter.*
|
import com.etesync.syncadapter.*
|
||||||
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
||||||
import com.etesync.syncadapter.journalmanager.Exceptions
|
import com.etesync.syncadapter.journalmanager.Exceptions
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.resource.LocalAddressBook
|
import com.etesync.syncadapter.resource.LocalAddressBook
|
||||||
import com.etesync.syncadapter.ui.DebugInfoActivity
|
import com.etesync.syncadapter.ui.DebugInfoActivity
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
@ -39,20 +40,20 @@ class ContactsSyncAdapterService : SyncAdapterService() {
|
|||||||
try {
|
try {
|
||||||
settings = AccountSettings(context, addressBook.mainAccount)
|
settings = AccountSettings(context, addressBook.mainAccount)
|
||||||
} catch (e: InvalidAccountException) {
|
} catch (e: InvalidAccountException) {
|
||||||
App.log.info("Skipping sync due to invalid account.")
|
Logger.log.info("Skipping sync due to invalid account.")
|
||||||
App.log.info(e.localizedMessage)
|
Logger.log.info(e.localizedMessage)
|
||||||
return
|
return
|
||||||
} catch (e: ContactsStorageException) {
|
} catch (e: ContactsStorageException) {
|
||||||
App.log.info("Skipping sync due to invalid account.")
|
Logger.log.info("Skipping sync due to invalid account.")
|
||||||
App.log.info(e.localizedMessage)
|
Logger.log.info(e.localizedMessage)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(settings))
|
if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(settings))
|
||||||
return
|
return
|
||||||
|
|
||||||
App.log.info("Synchronizing address book: " + addressBook.url)
|
Logger.log.info("Synchronizing address book: " + addressBook.url)
|
||||||
App.log.info("Taking settings from: " + addressBook.mainAccount)
|
Logger.log.info("Taking settings from: " + addressBook.mainAccount)
|
||||||
|
|
||||||
val principal = HttpUrl.get(settings.uri!!)!!
|
val principal = HttpUrl.get(settings.uri!!)!!
|
||||||
val syncManager = ContactsSyncManager(context, account, settings, extras, authority, provider, syncResult, addressBook, principal)
|
val syncManager = ContactsSyncManager(context, account, settings, extras, authority, provider, syncResult, addressBook, principal)
|
||||||
@ -79,7 +80,7 @@ class ContactsSyncAdapterService : SyncAdapterService() {
|
|||||||
notificationManager.notify(title, context.getString(syncPhase))
|
notificationManager.notify(title, context.getString(syncPhase))
|
||||||
}
|
}
|
||||||
|
|
||||||
App.log.info("Contacts sync complete")
|
Logger.log.info("Contacts sync complete")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,9 +16,13 @@ import at.bitfire.ical4android.CalendarStorageException
|
|||||||
import at.bitfire.vcard4android.BatchOperation
|
import at.bitfire.vcard4android.BatchOperation
|
||||||
import at.bitfire.vcard4android.Contact
|
import at.bitfire.vcard4android.Contact
|
||||||
import at.bitfire.vcard4android.ContactsStorageException
|
import at.bitfire.vcard4android.ContactsStorageException
|
||||||
import com.etesync.syncadapter.*
|
import com.etesync.syncadapter.AccountSettings
|
||||||
|
import com.etesync.syncadapter.Constants
|
||||||
|
import com.etesync.syncadapter.HttpClient
|
||||||
|
import com.etesync.syncadapter.R
|
||||||
import com.etesync.syncadapter.journalmanager.Exceptions
|
import com.etesync.syncadapter.journalmanager.Exceptions
|
||||||
import com.etesync.syncadapter.journalmanager.JournalEntryManager
|
import com.etesync.syncadapter.journalmanager.JournalEntryManager
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.model.CollectionInfo
|
import com.etesync.syncadapter.model.CollectionInfo
|
||||||
import com.etesync.syncadapter.model.SyncEntry
|
import com.etesync.syncadapter.model.SyncEntry
|
||||||
import com.etesync.syncadapter.resource.LocalAddress
|
import com.etesync.syncadapter.resource.LocalAddress
|
||||||
@ -66,7 +70,7 @@ constructor(context: Context, account: Account, settings: AccountSettings, extra
|
|||||||
val reallyDirty = localAddressBook.verifyDirty()
|
val reallyDirty = localAddressBook.verifyDirty()
|
||||||
val deleted = localAddressBook.findDeleted().size
|
val deleted = localAddressBook.findDeleted().size
|
||||||
if (extras.containsKey(ContentResolver.SYNC_EXTRAS_UPLOAD) && reallyDirty == 0 && deleted == 0) {
|
if (extras.containsKey(ContentResolver.SYNC_EXTRAS_UPLOAD) && reallyDirty == 0 && deleted == 0) {
|
||||||
App.log.info("This sync was called to up-sync dirty/deleted contacts, but no contacts have been changed")
|
Logger.log.info("This sync was called to up-sync dirty/deleted contacts, but no contacts have been changed")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,11 +100,11 @@ constructor(context: Context, account: Account, settings: AccountSettings, extra
|
|||||||
val batch = BatchOperation(addressBook.provider!!)
|
val batch = BatchOperation(addressBook.provider!!)
|
||||||
for (contact in addressBook.findDirtyContacts()) {
|
for (contact in addressBook.findDirtyContacts()) {
|
||||||
try {
|
try {
|
||||||
App.log.fine("Looking for changed group memberships of contact " + contact.fileName)
|
Logger.log.fine("Looking for changed group memberships of contact " + contact.fileName)
|
||||||
val cachedGroups = contact.getCachedGroupMemberships()
|
val cachedGroups = contact.getCachedGroupMemberships()
|
||||||
val currentGroups = contact.getGroupMemberships()
|
val currentGroups = contact.getGroupMemberships()
|
||||||
for (groupID in SetUtils.disjunction(cachedGroups, currentGroups)) {
|
for (groupID in SetUtils.disjunction(cachedGroups, currentGroups)) {
|
||||||
App.log.fine("Marking group as dirty: " + groupID!!)
|
Logger.log.fine("Marking group as dirty: " + groupID!!)
|
||||||
batch.enqueue(BatchOperation.Operation(
|
batch.enqueue(BatchOperation.Operation(
|
||||||
ContentProviderOperation.newUpdate(addressBook.syncAdapterURI(ContentUris.withAppendedId(ContactsContract.Groups.CONTENT_URI, groupID)))
|
ContentProviderOperation.newUpdate(addressBook.syncAdapterURI(ContentUris.withAppendedId(ContactsContract.Groups.CONTENT_URI, groupID)))
|
||||||
.withValue(ContactsContract.Groups.DIRTY, 1)
|
.withValue(ContactsContract.Groups.DIRTY, 1)
|
||||||
@ -118,7 +122,7 @@ constructor(context: Context, account: Account, settings: AccountSettings, extra
|
|||||||
override fun postProcess() {
|
override fun postProcess() {
|
||||||
super.postProcess()
|
super.postProcess()
|
||||||
/* VCard4 group handling: there are group contacts and individual contacts */
|
/* VCard4 group handling: there are group contacts and individual contacts */
|
||||||
App.log.info("Assigning memberships of downloaded contact groups")
|
Logger.log.info("Assigning memberships of downloaded contact groups")
|
||||||
LocalGroup.applyPendingMemberships(localAddressBook())
|
LocalGroup.applyPendingMemberships(localAddressBook())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,10 +140,10 @@ constructor(context: Context, account: Account, settings: AccountSettings, extra
|
|||||||
|
|
||||||
val contacts = Contact.fromReader(inputReader, downloader)
|
val contacts = Contact.fromReader(inputReader, downloader)
|
||||||
if (contacts.size == 0) {
|
if (contacts.size == 0) {
|
||||||
App.log.warning("Received VCard without data, ignoring")
|
Logger.log.warning("Received VCard without data, ignoring")
|
||||||
return
|
return
|
||||||
} else if (contacts.size > 1)
|
} else if (contacts.size > 1)
|
||||||
App.log.warning("Received multiple VCards, using first one")
|
Logger.log.warning("Received multiple VCards, using first one")
|
||||||
|
|
||||||
val contact = contacts[0]
|
val contact = contacts[0]
|
||||||
val local = localCollection!!.findByUid(contact.uid!!)
|
val local = localCollection!!.findByUid(contact.uid!!)
|
||||||
@ -148,10 +152,10 @@ constructor(context: Context, account: Account, settings: AccountSettings, extra
|
|||||||
processContact(contact, local)
|
processContact(contact, local)
|
||||||
} else {
|
} else {
|
||||||
if (local != null) {
|
if (local != null) {
|
||||||
App.log.info("Removing local record which has been deleted on the server")
|
Logger.log.info("Removing local record which has been deleted on the server")
|
||||||
local.delete()
|
local.delete()
|
||||||
} else {
|
} else {
|
||||||
App.log.warning("Tried deleting a non-existent record: " + contact.uid)
|
Logger.log.warning("Tried deleting a non-existent record: " + contact.uid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -162,7 +166,7 @@ constructor(context: Context, account: Account, settings: AccountSettings, extra
|
|||||||
val uuid = newData.uid
|
val uuid = newData.uid
|
||||||
// update local contact, if it exists
|
// update local contact, if it exists
|
||||||
if (local != null) {
|
if (local != null) {
|
||||||
App.log.log(Level.INFO, "Updating $uuid in local address book")
|
Logger.log.log(Level.INFO, "Updating $uuid in local address book")
|
||||||
|
|
||||||
if (local is LocalGroup && newData.group) {
|
if (local is LocalGroup && newData.group) {
|
||||||
// update group
|
// update group
|
||||||
@ -192,13 +196,13 @@ constructor(context: Context, account: Account, settings: AccountSettings, extra
|
|||||||
|
|
||||||
if (local == null) {
|
if (local == null) {
|
||||||
if (newData.group) {
|
if (newData.group) {
|
||||||
App.log.log(Level.INFO, "Creating local group", newData.uid)
|
Logger.log.log(Level.INFO, "Creating local group", newData.uid)
|
||||||
val group = LocalGroup(localAddressBook(), newData, uuid, uuid)
|
val group = LocalGroup(localAddressBook(), newData, uuid, uuid)
|
||||||
group.add()
|
group.add()
|
||||||
|
|
||||||
local = group
|
local = group
|
||||||
} else {
|
} else {
|
||||||
App.log.log(Level.INFO, "Creating local contact", newData.uid)
|
Logger.log.log(Level.INFO, "Creating local contact", newData.uid)
|
||||||
val contact = LocalContact(localAddressBook(), newData, uuid, uuid)
|
val contact = LocalContact(localAddressBook(), newData, uuid, uuid)
|
||||||
contact.add()
|
contact.add()
|
||||||
|
|
||||||
@ -222,13 +226,13 @@ constructor(context: Context, account: Account, settings: AccountSettings, extra
|
|||||||
val httpUrl = HttpUrl.parse(url)
|
val httpUrl = HttpUrl.parse(url)
|
||||||
|
|
||||||
if (httpUrl == null) {
|
if (httpUrl == null) {
|
||||||
App.log.log(Level.SEVERE, "Invalid external resource URL", url)
|
Logger.log.log(Level.SEVERE, "Invalid external resource URL", url)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val host = httpUrl.host()
|
val host = httpUrl.host()
|
||||||
if (host == null) {
|
if (host == null) {
|
||||||
App.log.log(Level.SEVERE, "External resource URL doesn't specify a host name", url)
|
Logger.log.log(Level.SEVERE, "External resource URL doesn't specify a host name", url)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,7 +257,7 @@ constructor(context: Context, account: Account, settings: AccountSettings, extra
|
|||||||
return body.bytes()
|
return body.bytes()
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
App.log.log(Level.SEVERE, "Couldn't download external resource", e)
|
Logger.log.log(Level.SEVERE, "Couldn't download external resource", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
@ -23,6 +23,7 @@ import com.etesync.syncadapter.*
|
|||||||
import com.etesync.syncadapter.journalmanager.Crypto
|
import com.etesync.syncadapter.journalmanager.Crypto
|
||||||
import com.etesync.syncadapter.journalmanager.Exceptions
|
import com.etesync.syncadapter.journalmanager.Exceptions
|
||||||
import com.etesync.syncadapter.journalmanager.JournalManager
|
import com.etesync.syncadapter.journalmanager.JournalManager
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
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.JournalModel
|
||||||
@ -45,14 +46,14 @@ abstract class SyncAdapterService : Service() {
|
|||||||
abstract class SyncAdapter(context: Context) : AbstractThreadedSyncAdapter(context, false) {
|
abstract class SyncAdapter(context: Context) : AbstractThreadedSyncAdapter(context, false) {
|
||||||
|
|
||||||
override fun onPerformSync(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
|
override fun onPerformSync(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
|
||||||
App.log.log(Level.INFO, "$authority sync of $account has been initiated.", extras.keySet().toTypedArray())
|
Logger.log.log(Level.INFO, "$authority sync of $account has been initiated.", extras.keySet().toTypedArray())
|
||||||
|
|
||||||
// required for dav4android (ServiceLoader)
|
// required for dav4android (ServiceLoader)
|
||||||
Thread.currentThread().contextClassLoader = context.classLoader
|
Thread.currentThread().contextClassLoader = context.classLoader
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSecurityException(account: Account, extras: Bundle, authority: String, syncResult: SyncResult) {
|
override fun onSecurityException(account: Account, extras: Bundle, authority: String, syncResult: SyncResult) {
|
||||||
App.log.log(Level.WARNING, "Security exception when opening content provider for $authority")
|
Logger.log.log(Level.WARNING, "Security exception when opening content provider for $authority")
|
||||||
syncResult.databaseError = true
|
syncResult.databaseError = true
|
||||||
|
|
||||||
val intent = Intent(context, PermissionsActivity::class.java)
|
val intent = Intent(context, PermissionsActivity::class.java)
|
||||||
@ -75,11 +76,11 @@ abstract class SyncAdapterService : Service() {
|
|||||||
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
val network = cm.activeNetworkInfo
|
val network = cm.activeNetworkInfo
|
||||||
if (network == null) {
|
if (network == null) {
|
||||||
App.log.info("No network available, stopping")
|
Logger.log.info("No network available, stopping")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (network.type != ConnectivityManager.TYPE_WIFI || !network.isConnected) {
|
if (network.type != ConnectivityManager.TYPE_WIFI || !network.isConnected) {
|
||||||
App.log.info("Not on connected WiFi, stopping")
|
Logger.log.info("Not on connected WiFi, stopping")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +90,7 @@ abstract class SyncAdapterService : Service() {
|
|||||||
val wifi = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
val wifi = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||||
val info = wifi.connectionInfo
|
val info = wifi.connectionInfo
|
||||||
if (info == null || onlySSID != info.ssid) {
|
if (info == null || onlySSID != info.ssid) {
|
||||||
App.log.info("Connected to wrong WiFi network (" + info!!.ssid + ", required: " + onlySSID + "), ignoring")
|
Logger.log.info("Connected to wrong WiFi network (" + info!!.ssid + ", required: " + onlySSID + "), ignoring")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,7 +107,7 @@ abstract class SyncAdapterService : Service() {
|
|||||||
|
|
||||||
@Throws(Exceptions.HttpException::class, Exceptions.IntegrityException::class, InvalidAccountException::class, Exceptions.GenericCryptoException::class)
|
@Throws(Exceptions.HttpException::class, Exceptions.IntegrityException::class, InvalidAccountException::class, Exceptions.GenericCryptoException::class)
|
||||||
internal fun run() {
|
internal fun run() {
|
||||||
App.log.info("Refreshing " + serviceType + " collections of service #" + serviceType.toString())
|
Logger.log.info("Refreshing " + serviceType + " collections of service #" + serviceType.toString())
|
||||||
|
|
||||||
val settings = AccountSettings(context, account)
|
val settings = AccountSettings(context, account)
|
||||||
val httpClient = HttpClient.create(context, settings)
|
val httpClient = HttpClient.create(context, settings)
|
||||||
@ -162,7 +163,7 @@ abstract class SyncAdapterService : Service() {
|
|||||||
for (pair in journals) {
|
for (pair in journals) {
|
||||||
val journal = pair.first
|
val journal = pair.first
|
||||||
val collection = pair.second
|
val collection = pair.second
|
||||||
App.log.log(Level.FINE, "Saving collection", journal!!.uid)
|
Logger.log.log(Level.FINE, "Saving collection", journal!!.uid)
|
||||||
|
|
||||||
collection!!.serviceID = service.id
|
collection!!.serviceID = service.id
|
||||||
val journalEntity = JournalEntity.fetchOrCreate(data, collection)
|
val journalEntity = JournalEntity.fetchOrCreate(data, collection)
|
||||||
@ -176,7 +177,7 @@ abstract class SyncAdapterService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (journalEntity in existing.values) {
|
for (journalEntity in existing.values) {
|
||||||
App.log.log(Level.FINE, "Deleting collection", journalEntity.uid)
|
Logger.log.log(Level.FINE, "Deleting collection", journalEntity.uid)
|
||||||
|
|
||||||
journalEntity.isDeleted = true
|
journalEntity.isDeleted = true
|
||||||
data.update(journalEntity)
|
data.update(journalEntity)
|
||||||
|
@ -21,6 +21,7 @@ import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
|||||||
import com.etesync.syncadapter.journalmanager.Crypto
|
import com.etesync.syncadapter.journalmanager.Crypto
|
||||||
import com.etesync.syncadapter.journalmanager.Exceptions
|
import com.etesync.syncadapter.journalmanager.Exceptions
|
||||||
import com.etesync.syncadapter.journalmanager.JournalEntryManager
|
import com.etesync.syncadapter.journalmanager.JournalEntryManager
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.model.*
|
import com.etesync.syncadapter.model.*
|
||||||
import com.etesync.syncadapter.model.SyncEntry.Actions.ADD
|
import com.etesync.syncadapter.model.SyncEntry.Actions.ADD
|
||||||
import com.etesync.syncadapter.resource.LocalCollection
|
import com.etesync.syncadapter.resource.LocalCollection
|
||||||
@ -96,7 +97,7 @@ constructor(protected val context: Context, protected val account: Account, prot
|
|||||||
notificationManager = NotificationHelper(context, journalUid, notificationId())
|
notificationManager = NotificationHelper(context, journalUid, notificationId())
|
||||||
notificationManager.cancel()
|
notificationManager.cancel()
|
||||||
|
|
||||||
App.log.info(String.format(Locale.getDefault(), "Syncing collection %s (version: %d)", journalUid, info.version))
|
Logger.log.info(String.format(Locale.getDefault(), "Syncing collection %s (version: %d)", journalUid, info.version))
|
||||||
|
|
||||||
if (journalEntity.encryptedKey != null) {
|
if (journalEntity.encryptedKey != null) {
|
||||||
crypto = Crypto.CryptoManager(info.version, settings.keyPair!!, journalEntity.encryptedKey)
|
crypto = Crypto.CryptoManager(info.version, settings.keyPair!!, journalEntity.encryptedKey)
|
||||||
@ -111,35 +112,35 @@ constructor(protected val context: Context, protected val account: Account, prot
|
|||||||
fun performSync() {
|
fun performSync() {
|
||||||
var syncPhase = R.string.sync_phase_prepare
|
var syncPhase = R.string.sync_phase_prepare
|
||||||
try {
|
try {
|
||||||
App.log.info("Sync phase: " + context.getString(syncPhase))
|
Logger.log.info("Sync phase: " + context.getString(syncPhase))
|
||||||
if (!prepare()) {
|
if (!prepare()) {
|
||||||
App.log.info("No reason to synchronize, aborting")
|
Logger.log.info("No reason to synchronize, aborting")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Thread.interrupted())
|
if (Thread.interrupted())
|
||||||
throw InterruptedException()
|
throw InterruptedException()
|
||||||
syncPhase = R.string.sync_phase_query_capabilities
|
syncPhase = R.string.sync_phase_query_capabilities
|
||||||
App.log.info("Sync phase: " + context.getString(syncPhase))
|
Logger.log.info("Sync phase: " + context.getString(syncPhase))
|
||||||
queryCapabilities()
|
queryCapabilities()
|
||||||
|
|
||||||
if (Thread.interrupted())
|
if (Thread.interrupted())
|
||||||
throw InterruptedException()
|
throw InterruptedException()
|
||||||
syncPhase = R.string.sync_phase_prepare_local
|
syncPhase = R.string.sync_phase_prepare_local
|
||||||
App.log.info("Sync phase: " + context.getString(syncPhase))
|
Logger.log.info("Sync phase: " + context.getString(syncPhase))
|
||||||
prepareLocal()
|
prepareLocal()
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (Thread.interrupted())
|
if (Thread.interrupted())
|
||||||
throw InterruptedException()
|
throw InterruptedException()
|
||||||
syncPhase = R.string.sync_phase_fetch_entries
|
syncPhase = R.string.sync_phase_fetch_entries
|
||||||
App.log.info("Sync phase: " + context.getString(syncPhase))
|
Logger.log.info("Sync phase: " + context.getString(syncPhase))
|
||||||
fetchEntries()
|
fetchEntries()
|
||||||
|
|
||||||
if (Thread.interrupted())
|
if (Thread.interrupted())
|
||||||
throw InterruptedException()
|
throw InterruptedException()
|
||||||
syncPhase = R.string.sync_phase_apply_remote_entries
|
syncPhase = R.string.sync_phase_apply_remote_entries
|
||||||
App.log.info("Sync phase: " + context.getString(syncPhase))
|
Logger.log.info("Sync phase: " + context.getString(syncPhase))
|
||||||
applyRemoteEntries()
|
applyRemoteEntries()
|
||||||
} while (remoteEntries!!.size == MAX_FETCH)
|
} while (remoteEntries!!.size == MAX_FETCH)
|
||||||
|
|
||||||
@ -148,13 +149,13 @@ constructor(protected val context: Context, protected val account: Account, prot
|
|||||||
if (Thread.interrupted())
|
if (Thread.interrupted())
|
||||||
throw InterruptedException()
|
throw InterruptedException()
|
||||||
syncPhase = R.string.sync_phase_create_local_entries
|
syncPhase = R.string.sync_phase_create_local_entries
|
||||||
App.log.info("Sync phase: " + context.getString(syncPhase))
|
Logger.log.info("Sync phase: " + context.getString(syncPhase))
|
||||||
createLocalEntries()
|
createLocalEntries()
|
||||||
|
|
||||||
if (Thread.interrupted())
|
if (Thread.interrupted())
|
||||||
throw InterruptedException()
|
throw InterruptedException()
|
||||||
syncPhase = R.string.sync_phase_apply_local_entries
|
syncPhase = R.string.sync_phase_apply_local_entries
|
||||||
App.log.info("Sync phase: " + context.getString(syncPhase))
|
Logger.log.info("Sync phase: " + context.getString(syncPhase))
|
||||||
/* FIXME: Skipping this now, because we already override with remote.
|
/* FIXME: Skipping this now, because we already override with remote.
|
||||||
applyLocalEntries();
|
applyLocalEntries();
|
||||||
*/
|
*/
|
||||||
@ -162,7 +163,7 @@ constructor(protected val context: Context, protected val account: Account, prot
|
|||||||
if (Thread.interrupted())
|
if (Thread.interrupted())
|
||||||
throw InterruptedException()
|
throw InterruptedException()
|
||||||
syncPhase = R.string.sync_phase_push_entries
|
syncPhase = R.string.sync_phase_push_entries
|
||||||
App.log.info("Sync phase: " + context.getString(syncPhase))
|
Logger.log.info("Sync phase: " + context.getString(syncPhase))
|
||||||
pushEntries()
|
pushEntries()
|
||||||
} while (localEntries!!.size == MAX_PUSH)
|
} while (localEntries!!.size == MAX_PUSH)
|
||||||
|
|
||||||
@ -170,7 +171,7 @@ constructor(protected val context: Context, protected val account: Account, prot
|
|||||||
if (Thread.interrupted())
|
if (Thread.interrupted())
|
||||||
throw InterruptedException()
|
throw InterruptedException()
|
||||||
syncPhase = R.string.sync_phase_post_processing
|
syncPhase = R.string.sync_phase_post_processing
|
||||||
App.log.info("Sync phase: " + context.getString(syncPhase))
|
Logger.log.info("Sync phase: " + context.getString(syncPhase))
|
||||||
postProcess()
|
postProcess()
|
||||||
|
|
||||||
if (numDiscarded > 0) {
|
if (numDiscarded > 0) {
|
||||||
@ -178,9 +179,9 @@ constructor(protected val context: Context, protected val account: Account, prot
|
|||||||
}
|
}
|
||||||
notifyUserOnSync()
|
notifyUserOnSync()
|
||||||
|
|
||||||
App.log.info("Finished sync with CTag=$remoteCTag")
|
Logger.log.info("Finished sync with CTag=$remoteCTag")
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
App.log.log(Level.WARNING, "I/O exception during sync, trying again later", e)
|
Logger.log.log(Level.WARNING, "I/O exception during sync, trying again later", e)
|
||||||
syncResult.stats.numIoExceptions++
|
syncResult.stats.numIoExceptions++
|
||||||
} catch (e: Exceptions.ServiceUnavailableException) {
|
} catch (e: Exceptions.ServiceUnavailableException) {
|
||||||
syncResult.stats.numIoExceptions++
|
syncResult.stats.numIoExceptions++
|
||||||
@ -298,13 +299,13 @@ constructor(protected val context: Context, protected val account: Account, prot
|
|||||||
throw InterruptedException()
|
throw InterruptedException()
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
App.log.info("Processing (" + i.toString() + "/" + strTotal + ") " + entry.toString())
|
Logger.log.info("Processing (" + i.toString() + "/" + strTotal + ") " + entry.toString())
|
||||||
|
|
||||||
val cEntry = SyncEntry.fromJournalEntry(crypto, entry)
|
val cEntry = SyncEntry.fromJournalEntry(crypto, entry)
|
||||||
if (cEntry.isAction(SyncEntry.Actions.DELETE)) {
|
if (cEntry.isAction(SyncEntry.Actions.DELETE)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
App.log.info("Processing resource for journal entry")
|
Logger.log.info("Processing resource for journal entry")
|
||||||
processSyncEntry(cEntry)
|
processSyncEntry(cEntry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -333,7 +334,7 @@ constructor(protected val context: Context, protected val account: Account, prot
|
|||||||
remoteEntries = journal!!.list(crypto, remoteCTag, MAX_FETCH)
|
remoteEntries = journal!!.list(crypto, remoteCTag, MAX_FETCH)
|
||||||
}
|
}
|
||||||
|
|
||||||
App.log.info("Fetched " + remoteEntries!!.size.toString() + " entries")
|
Logger.log.info("Fetched " + remoteEntries!!.size.toString() + " entries")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class, ContactsStorageException::class, CalendarStorageException::class, InvalidCalendarException::class, InterruptedException::class)
|
@Throws(IOException::class, ContactsStorageException::class, CalendarStorageException::class, InvalidCalendarException::class, InterruptedException::class)
|
||||||
@ -347,10 +348,10 @@ constructor(protected val context: Context, protected val account: Account, prot
|
|||||||
throw InterruptedException()
|
throw InterruptedException()
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
App.log.info("Processing (" + i.toString() + "/" + strTotal + ") " + entry.toString())
|
Logger.log.info("Processing (" + i.toString() + "/" + strTotal + ") " + entry.toString())
|
||||||
|
|
||||||
val cEntry = SyncEntry.fromJournalEntry(crypto, entry)
|
val cEntry = SyncEntry.fromJournalEntry(crypto, entry)
|
||||||
App.log.info("Processing resource for journal entry")
|
Logger.log.info("Processing resource for journal entry")
|
||||||
processSyncEntry(cEntry)
|
processSyncEntry(cEntry)
|
||||||
|
|
||||||
persistSyncEntry(entry.uid, cEntry)
|
persistSyncEntry(entry.uid, cEntry)
|
||||||
@ -394,7 +395,7 @@ constructor(protected val context: Context, protected val account: Account, prot
|
|||||||
if (pushed-- <= 0) {
|
if (pushed-- <= 0) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
App.log.info("Added/changed resource with UUID: " + local.uuid)
|
Logger.log.info("Added/changed resource with UUID: " + local.uuid)
|
||||||
local.clearDirty(local.uuid!!)
|
local.clearDirty(local.uuid!!)
|
||||||
}
|
}
|
||||||
if (left > 0) {
|
if (left > 0) {
|
||||||
@ -402,7 +403,7 @@ constructor(protected val context: Context, protected val account: Account, prot
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pushed > 0) {
|
if (pushed > 0) {
|
||||||
App.log.severe("Unprocessed localentries left, this should never happen!")
|
Logger.log.severe("Unprocessed localentries left, this should never happen!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -470,7 +471,7 @@ constructor(protected val context: Context, protected val account: Account, prot
|
|||||||
|
|
||||||
if (journalEntity.isReadOnly) {
|
if (journalEntity.isReadOnly) {
|
||||||
for (local in localList) {
|
for (local in localList) {
|
||||||
App.log.info("Restoring locally deleted resource on a read only collection: ${local.uuid}")
|
Logger.log.info("Restoring locally deleted resource on a read only collection: ${local.uuid}")
|
||||||
local.resetDeleted()
|
local.resetDeleted()
|
||||||
numDiscarded++
|
numDiscarded++
|
||||||
}
|
}
|
||||||
@ -480,9 +481,9 @@ constructor(protected val context: Context, protected val account: Account, prot
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
if (local.uuid != null) {
|
if (local.uuid != null) {
|
||||||
App.log.info(local.uuid + " has been deleted locally -> deleting from server")
|
Logger.log.info(local.uuid + " has been deleted locally -> deleting from server")
|
||||||
} else {
|
} else {
|
||||||
App.log.fine("Entry deleted before ever syncing - genarting a UUID")
|
Logger.log.fine("Entry deleted before ever syncing - genarting a UUID")
|
||||||
local.prepareForUpload()
|
local.prepareForUpload()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -499,7 +500,7 @@ constructor(protected val context: Context, protected val account: Account, prot
|
|||||||
protected open fun prepareDirty() {
|
protected open fun prepareDirty() {
|
||||||
if (journalEntity.isReadOnly) {
|
if (journalEntity.isReadOnly) {
|
||||||
for (local in localDirty) {
|
for (local in localDirty) {
|
||||||
App.log.info("Restoring locally modified resource on a read only collection: ${local.uuid}")
|
Logger.log.info("Restoring locally modified resource on a read only collection: ${local.uuid}")
|
||||||
if (local.uuid == null) {
|
if (local.uuid == null) {
|
||||||
// If it was only local, delete.
|
// If it was only local, delete.
|
||||||
local.delete()
|
local.delete()
|
||||||
@ -512,13 +513,13 @@ constructor(protected val context: Context, protected val account: Account, prot
|
|||||||
localDirty = LinkedList()
|
localDirty = LinkedList()
|
||||||
} else {
|
} else {
|
||||||
// assign file names and UIDs to new entries
|
// assign file names and UIDs to new entries
|
||||||
App.log.info("Looking for local entries without a uuid")
|
Logger.log.info("Looking for local entries without a uuid")
|
||||||
for (local in localDirty) {
|
for (local in localDirty) {
|
||||||
if (local.uuid != null) {
|
if (local.uuid != null) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
App.log.fine("Found local record without file name; generating file name/UID if necessary")
|
Logger.log.fine("Found local record without file name; generating file name/UID if necessary")
|
||||||
local.prepareForUpload()
|
local.prepareForUpload()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,11 @@ import android.content.SyncResult
|
|||||||
import android.database.sqlite.SQLiteException
|
import android.database.sqlite.SQLiteException
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.CalendarContract
|
|
||||||
import at.bitfire.ical4android.AndroidTaskList
|
import at.bitfire.ical4android.AndroidTaskList
|
||||||
import at.bitfire.ical4android.TaskProvider
|
import at.bitfire.ical4android.TaskProvider
|
||||||
import com.etesync.syncadapter.*
|
import com.etesync.syncadapter.*
|
||||||
import com.etesync.syncadapter.journalmanager.Exceptions
|
import com.etesync.syncadapter.journalmanager.Exceptions
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
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.JournalModel
|
||||||
@ -72,7 +72,7 @@ class TasksSyncAdapterService: SyncAdapterService() {
|
|||||||
val principal = HttpUrl.get(accountSettings.uri!!)!!
|
val principal = HttpUrl.get(accountSettings.uri!!)!!
|
||||||
|
|
||||||
for (taskList in AndroidTaskList.find(account, taskProvider, LocalTaskList.Factory, "${TaskContract.TaskLists.SYNC_ENABLED}!=0", null)) {
|
for (taskList in AndroidTaskList.find(account, taskProvider, LocalTaskList.Factory, "${TaskContract.TaskLists.SYNC_ENABLED}!=0", null)) {
|
||||||
App.log.info("Synchronizing task list #${taskList.id} [${taskList.syncId}]")
|
Logger.log.info("Synchronizing task list #${taskList.id} [${taskList.syncId}]")
|
||||||
val tasksSyncManager = TasksSyncManager(context, account, accountSettings, extras, authority, syncResult, taskList, principal);
|
val tasksSyncManager = TasksSyncManager(context, account, accountSettings, extras, authority, syncResult, taskList, principal);
|
||||||
tasksSyncManager.performSync()
|
tasksSyncManager.performSync()
|
||||||
}
|
}
|
||||||
@ -83,7 +83,7 @@ class TasksSyncAdapterService: SyncAdapterService() {
|
|||||||
// Ignore
|
// Ignore
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
if (e is SQLiteException) {
|
if (e is SQLiteException) {
|
||||||
App.log.log(Level.SEVERE, "Couldn't prepare local task list", e)
|
Logger.log.log(Level.SEVERE, "Couldn't prepare local task list", e)
|
||||||
syncResult.databaseError = true
|
syncResult.databaseError = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ class TasksSyncAdapterService: SyncAdapterService() {
|
|||||||
notificationManager.notify(title, context.getString(syncPhase))
|
notificationManager.notify(title, context.getString(syncPhase))
|
||||||
}
|
}
|
||||||
|
|
||||||
App.log.info("Task sync complete")
|
Logger.log.info("Task sync complete")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateLocalTaskLists(provider: TaskProvider, account: Account, settings: AccountSettings) {
|
private fun updateLocalTaskLists(provider: TaskProvider, account: Account, settings: AccountSettings) {
|
||||||
@ -131,11 +131,11 @@ class TasksSyncAdapterService: SyncAdapterService() {
|
|||||||
val url = taskList.url
|
val url = taskList.url
|
||||||
val journalEntity = remote[url]
|
val journalEntity = remote[url]
|
||||||
if (journalEntity == null) {
|
if (journalEntity == null) {
|
||||||
App.log.fine("Deleting obsolete local task list $url")
|
Logger.log.fine("Deleting obsolete local task list $url")
|
||||||
taskList.delete()
|
taskList.delete()
|
||||||
} else {
|
} else {
|
||||||
// remote CollectionInfo found for this local collection, update data
|
// remote CollectionInfo found for this local collection, update data
|
||||||
App.log.fine("Updating local task list $url with $journalEntity")
|
Logger.log.fine("Updating local task list $url with $journalEntity")
|
||||||
taskList.update(journalEntity, updateColors)
|
taskList.update(journalEntity, updateColors)
|
||||||
// we already have a local tasks for this remote collection, don't take into consideration anymore
|
// we already have a local tasks for this remote collection, don't take into consideration anymore
|
||||||
remote.remove(url)
|
remote.remove(url)
|
||||||
@ -145,7 +145,7 @@ class TasksSyncAdapterService: SyncAdapterService() {
|
|||||||
// create new local taskss
|
// create new local taskss
|
||||||
for (url in remote.keys) {
|
for (url in remote.keys) {
|
||||||
val journalEntity = remote[url]!!
|
val journalEntity = remote[url]!!
|
||||||
App.log.info("Adding local task list $journalEntity")
|
Logger.log.info("Adding local task list $journalEntity")
|
||||||
LocalTaskList.create(account, provider, journalEntity)
|
LocalTaskList.create(account, provider, journalEntity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,10 @@ import android.content.SyncResult
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import at.bitfire.ical4android.Task
|
import at.bitfire.ical4android.Task
|
||||||
import com.etesync.syncadapter.AccountSettings
|
import com.etesync.syncadapter.AccountSettings
|
||||||
import com.etesync.syncadapter.App
|
|
||||||
import com.etesync.syncadapter.Constants
|
import com.etesync.syncadapter.Constants
|
||||||
import com.etesync.syncadapter.R
|
import com.etesync.syncadapter.R
|
||||||
import com.etesync.syncadapter.journalmanager.JournalEntryManager
|
import com.etesync.syncadapter.journalmanager.JournalEntryManager
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.model.CollectionInfo
|
import com.etesync.syncadapter.model.CollectionInfo
|
||||||
import com.etesync.syncadapter.model.SyncEntry
|
import com.etesync.syncadapter.model.SyncEntry
|
||||||
import com.etesync.syncadapter.resource.LocalTask
|
import com.etesync.syncadapter.resource.LocalTask
|
||||||
@ -73,10 +73,10 @@ class TasksSyncManager(
|
|||||||
|
|
||||||
val tasks = Task.fromReader(inputReader)
|
val tasks = Task.fromReader(inputReader)
|
||||||
if (tasks.size == 0) {
|
if (tasks.size == 0) {
|
||||||
App.log.warning("Received VCard without data, ignoring")
|
Logger.log.warning("Received VCard without data, ignoring")
|
||||||
return
|
return
|
||||||
} else if (tasks.size > 1) {
|
} else if (tasks.size > 1) {
|
||||||
App.log.warning("Received multiple VCALs, using first one")
|
Logger.log.warning("Received multiple VCALs, using first one")
|
||||||
}
|
}
|
||||||
|
|
||||||
val event = tasks[0]
|
val event = tasks[0]
|
||||||
@ -86,10 +86,10 @@ class TasksSyncManager(
|
|||||||
processTask(event, local)
|
processTask(event, local)
|
||||||
} else {
|
} else {
|
||||||
if (local != null) {
|
if (local != null) {
|
||||||
App.log.info("Removing local record #" + local.id + " which has been deleted on the server")
|
Logger.log.info("Removing local record #" + local.id + " which has been deleted on the server")
|
||||||
local.delete()
|
local.delete()
|
||||||
} else {
|
} else {
|
||||||
App.log.warning("Tried deleting a non-existent record: " + event.uid)
|
Logger.log.warning("Tried deleting a non-existent record: " + event.uid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,12 +98,12 @@ class TasksSyncManager(
|
|||||||
var localTask = _localTask
|
var localTask = _localTask
|
||||||
// delete local Task, if it exists
|
// delete local Task, if it exists
|
||||||
if (localTask != null) {
|
if (localTask != null) {
|
||||||
App.log.info("Updating " + newData.uid + " in local calendar")
|
Logger.log.info("Updating " + newData.uid + " in local calendar")
|
||||||
localTask.eTag = newData.uid
|
localTask.eTag = newData.uid
|
||||||
localTask.update(newData)
|
localTask.update(newData)
|
||||||
syncResult.stats.numUpdates++
|
syncResult.stats.numUpdates++
|
||||||
} else {
|
} else {
|
||||||
App.log.info("Adding " + newData.uid + " to local calendar")
|
Logger.log.info("Adding " + newData.uid + " to local calendar")
|
||||||
localTask = LocalTask(localTaskList(), newData, newData.uid, newData.uid)
|
localTask = LocalTask(localTaskList(), newData, newData.uid, newData.uid)
|
||||||
localTask.add()
|
localTask.add()
|
||||||
syncResult.stats.numInserts++
|
syncResult.stats.numInserts++
|
||||||
|
@ -11,15 +11,6 @@ package com.etesync.syncadapter.ui
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.google.android.material.tabs.TabLayout
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.FragmentManager
|
|
||||||
import androidx.fragment.app.FragmentPagerAdapter
|
|
||||||
import androidx.loader.app.LoaderManager
|
|
||||||
import androidx.loader.content.AsyncTaskLoader
|
|
||||||
import androidx.loader.content.Loader
|
|
||||||
import androidx.viewpager.widget.ViewPager
|
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import android.text.Html
|
import android.text.Html
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
import android.text.util.Linkify
|
import android.text.util.Linkify
|
||||||
@ -27,12 +18,21 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import androidx.fragment.app.FragmentPagerAdapter
|
||||||
|
import androidx.loader.app.LoaderManager
|
||||||
|
import androidx.loader.content.AsyncTaskLoader
|
||||||
|
import androidx.loader.content.Loader
|
||||||
|
import androidx.viewpager.widget.ViewPager
|
||||||
import com.etesync.syncadapter.App
|
import com.etesync.syncadapter.App
|
||||||
import com.etesync.syncadapter.BuildConfig
|
import com.etesync.syncadapter.BuildConfig
|
||||||
import com.etesync.syncadapter.Constants
|
import com.etesync.syncadapter.Constants
|
||||||
import com.etesync.syncadapter.R
|
import com.etesync.syncadapter.R
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
|
import com.google.android.material.tabs.TabLayout
|
||||||
import ezvcard.Ezvcard
|
import ezvcard.Ezvcard
|
||||||
import org.apache.commons.lang3.time.DateFormatUtils
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ class AboutActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun loadInBackground(): Spanned? {
|
override fun loadInBackground(): Spanned? {
|
||||||
App.log.fine("Loading license file $fileName")
|
Logger.log.fine("Loading license file $fileName")
|
||||||
try {
|
try {
|
||||||
val inputStream = context.resources.assets.open(fileName)
|
val inputStream = context.resources.assets.open(fileName)
|
||||||
val raw = inputStream.readBytes()
|
val raw = inputStream.readBytes()
|
||||||
@ -148,7 +148,7 @@ class AboutActivity : BaseActivity() {
|
|||||||
content = Html.fromHtml(String(raw))
|
content = Html.fromHtml(String(raw))
|
||||||
return content
|
return content
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
App.log.log(Level.SEVERE, "Couldn't read license file", e)
|
Logger.log.log(Level.SEVERE, "Couldn't read license file", e)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,17 +19,17 @@ import android.os.Bundle
|
|||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.provider.CalendarContract
|
import android.provider.CalendarContract
|
||||||
import android.provider.ContactsContract
|
import android.provider.ContactsContract
|
||||||
import com.google.android.material.snackbar.Snackbar
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.appcompat.widget.Toolbar
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import at.bitfire.ical4android.TaskProvider
|
import at.bitfire.ical4android.TaskProvider
|
||||||
import at.bitfire.vcard4android.ContactsStorageException
|
import at.bitfire.vcard4android.ContactsStorageException
|
||||||
import com.etesync.syncadapter.*
|
import com.etesync.syncadapter.*
|
||||||
import com.etesync.syncadapter.journalmanager.Crypto
|
import com.etesync.syncadapter.journalmanager.Crypto
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
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.ServiceEntity
|
import com.etesync.syncadapter.model.ServiceEntity
|
||||||
@ -40,6 +40,7 @@ import com.etesync.syncadapter.ui.setup.SetupUserInfoFragment
|
|||||||
import com.etesync.syncadapter.utils.HintManager
|
import com.etesync.syncadapter.utils.HintManager
|
||||||
import com.etesync.syncadapter.utils.ShowcaseBuilder
|
import com.etesync.syncadapter.utils.ShowcaseBuilder
|
||||||
import com.etesync.syncadapter.utils.packageInstalled
|
import com.etesync.syncadapter.utils.packageInstalled
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import tourguide.tourguide.ToolTip
|
import tourguide.tourguide.ToolTip
|
||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
|
|
||||||
@ -418,7 +419,7 @@ class AccountActivity : BaseActivity(), Toolbar.OnMenuItemClickListener, PopupMe
|
|||||||
if (future.result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT))
|
if (future.result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT))
|
||||||
finish()
|
finish()
|
||||||
} catch(e: Exception) {
|
} catch(e: Exception) {
|
||||||
App.log.log(Level.SEVERE, "Couldn't remove account", e)
|
Logger.log.log(Level.SEVERE, "Couldn't remove account", e)
|
||||||
}
|
}
|
||||||
}, null)
|
}, null)
|
||||||
else
|
else
|
||||||
@ -427,7 +428,7 @@ class AccountActivity : BaseActivity(), Toolbar.OnMenuItemClickListener, PopupMe
|
|||||||
if (future.result)
|
if (future.result)
|
||||||
finish()
|
finish()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
App.log.log(Level.SEVERE, "Couldn't remove account", e)
|
Logger.log.log(Level.SEVERE, "Couldn't remove account", e)
|
||||||
}
|
}
|
||||||
}, null)
|
}, null)
|
||||||
}
|
}
|
||||||
|
@ -15,17 +15,18 @@ import android.content.Intent
|
|||||||
import android.content.SyncStatusObserver
|
import android.content.SyncStatusObserver
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.CalendarContract
|
import android.provider.CalendarContract
|
||||||
import androidx.loader.app.LoaderManager
|
import android.text.TextUtils
|
||||||
|
import android.view.MenuItem
|
||||||
import androidx.core.app.NavUtils
|
import androidx.core.app.NavUtils
|
||||||
|
import androidx.loader.app.LoaderManager
|
||||||
import androidx.loader.content.AsyncTaskLoader
|
import androidx.loader.content.AsyncTaskLoader
|
||||||
import androidx.loader.content.Loader
|
import androidx.loader.content.Loader
|
||||||
import androidx.preference.*
|
import androidx.preference.*
|
||||||
import android.text.TextUtils
|
|
||||||
import android.view.MenuItem
|
|
||||||
import at.bitfire.ical4android.TaskProvider
|
import at.bitfire.ical4android.TaskProvider
|
||||||
import com.etesync.syncadapter.*
|
import com.etesync.syncadapter.*
|
||||||
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
||||||
import com.etesync.syncadapter.R
|
import com.etesync.syncadapter.R
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.ui.setup.LoginCredentials
|
import com.etesync.syncadapter.ui.setup.LoginCredentials
|
||||||
import com.etesync.syncadapter.ui.setup.LoginCredentialsChangeFragment
|
import com.etesync.syncadapter.ui.setup.LoginCredentialsChangeFragment
|
||||||
|
|
||||||
@ -185,7 +186,7 @@ class AccountSettingsActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onStatusChanged(which: Int) {
|
override fun onStatusChanged(which: Int) {
|
||||||
App.log.fine("Reloading account settings")
|
Logger.log.fine("Reloading account settings")
|
||||||
forceLoad()
|
forceLoad()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,17 +13,17 @@ import android.app.ProgressDialog
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
import com.etesync.syncadapter.AccountSettings
|
import com.etesync.syncadapter.AccountSettings
|
||||||
import com.etesync.syncadapter.App
|
|
||||||
import com.etesync.syncadapter.HttpClient
|
import com.etesync.syncadapter.HttpClient
|
||||||
import com.etesync.syncadapter.R
|
import com.etesync.syncadapter.R
|
||||||
import com.etesync.syncadapter.journalmanager.Crypto
|
import com.etesync.syncadapter.journalmanager.Crypto
|
||||||
import com.etesync.syncadapter.journalmanager.JournalManager
|
import com.etesync.syncadapter.journalmanager.JournalManager
|
||||||
import com.etesync.syncadapter.journalmanager.UserInfoManager
|
import com.etesync.syncadapter.journalmanager.UserInfoManager
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.syncadapter.requestSync
|
import com.etesync.syncadapter.syncadapter.requestSync
|
||||||
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import org.jetbrains.anko.doAsync
|
import org.jetbrains.anko.doAsync
|
||||||
import org.jetbrains.anko.uiThread
|
import org.jetbrains.anko.uiThread
|
||||||
@ -64,9 +64,9 @@ open class ChangeEncryptionPasswordActivity : BaseActivity() {
|
|||||||
val httpClient = HttpClient.create(this, settings)
|
val httpClient = HttpClient.create(this, settings)
|
||||||
|
|
||||||
doAsync {
|
doAsync {
|
||||||
App.log.info("Started deriving old key")
|
Logger.log.info("Started deriving old key")
|
||||||
val old_key = Crypto.deriveKey(account.name, old_password)
|
val old_key = Crypto.deriveKey(account.name, old_password)
|
||||||
App.log.info("Finished deriving old key")
|
Logger.log.info("Finished deriving old key")
|
||||||
|
|
||||||
var cryptoManager: Crypto.CryptoManager
|
var cryptoManager: Crypto.CryptoManager
|
||||||
val principal = HttpUrl.get(settings.uri!!)!!
|
val principal = HttpUrl.get(settings.uri!!)!!
|
||||||
@ -74,19 +74,19 @@ open class ChangeEncryptionPasswordActivity : BaseActivity() {
|
|||||||
try {
|
try {
|
||||||
val userInfoManager = UserInfoManager(httpClient, principal)
|
val userInfoManager = UserInfoManager(httpClient, principal)
|
||||||
val userInfo = userInfoManager.fetch(account.name)!!
|
val userInfo = userInfoManager.fetch(account.name)!!
|
||||||
App.log.info("Fetched userInfo for " + account.name)
|
Logger.log.info("Fetched userInfo for " + account.name)
|
||||||
cryptoManager = Crypto.CryptoManager(userInfo.version!!.toInt(), old_key, "userInfo")
|
cryptoManager = Crypto.CryptoManager(userInfo.version!!.toInt(), old_key, "userInfo")
|
||||||
userInfo.verify(cryptoManager)
|
userInfo.verify(cryptoManager)
|
||||||
|
|
||||||
App.log.info("Started deriving new key")
|
Logger.log.info("Started deriving new key")
|
||||||
val new_key = Crypto.deriveKey(account.name, new_password)
|
val new_key = Crypto.deriveKey(account.name, new_password)
|
||||||
App.log.info("Finished deriving new key")
|
Logger.log.info("Finished deriving new key")
|
||||||
|
|
||||||
val userInfoContent = userInfo.getContent(cryptoManager)!!
|
val userInfoContent = userInfo.getContent(cryptoManager)!!
|
||||||
cryptoManager = Crypto.CryptoManager(userInfo.version.toInt(), new_key, "userInfo")
|
cryptoManager = Crypto.CryptoManager(userInfo.version.toInt(), new_key, "userInfo")
|
||||||
userInfo.setContent(cryptoManager, userInfoContent)
|
userInfo.setContent(cryptoManager, userInfoContent)
|
||||||
|
|
||||||
App.log.info("Fetching journal list")
|
Logger.log.info("Fetching journal list")
|
||||||
val membersToAdd = LinkedList<Pair<JournalManager.Journal, ByteArray?>>()
|
val membersToAdd = LinkedList<Pair<JournalManager.Journal, ByteArray?>>()
|
||||||
val journalManager = JournalManager(httpClient, principal)
|
val journalManager = JournalManager(httpClient, principal)
|
||||||
val journals = journalManager.list()
|
val journals = journalManager.list()
|
||||||
@ -102,13 +102,13 @@ open class ChangeEncryptionPasswordActivity : BaseActivity() {
|
|||||||
cryptoManager = Crypto.CryptoManager(journal.version, old_key, journal.uid!!)
|
cryptoManager = Crypto.CryptoManager(journal.version, old_key, journal.uid!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
App.log.info("Converting journal ${journal.uid}")
|
Logger.log.info("Converting journal ${journal.uid}")
|
||||||
journal.verify(cryptoManager)
|
journal.verify(cryptoManager)
|
||||||
|
|
||||||
membersToAdd.add(Pair(journal, cryptoManager.getEncryptedKey(settings.keyPair!!, userInfo.pubkey!!)))
|
membersToAdd.add(Pair(journal, cryptoManager.getEncryptedKey(settings.keyPair!!, userInfo.pubkey!!)))
|
||||||
}
|
}
|
||||||
|
|
||||||
App.log.info("Finished converting account. Uploading changes")
|
Logger.log.info("Finished converting account. Uploading changes")
|
||||||
userInfoManager.update(userInfo)
|
userInfoManager.update(userInfo)
|
||||||
|
|
||||||
for ((journal, encryptedKey) in membersToAdd) {
|
for ((journal, encryptedKey) in membersToAdd) {
|
||||||
@ -116,13 +116,13 @@ open class ChangeEncryptionPasswordActivity : BaseActivity() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
App.log.info("Uploading journal ${journal.uid}")
|
Logger.log.info("Uploading journal ${journal.uid}")
|
||||||
val member = JournalManager.Member(account.name, encryptedKey!!)
|
val member = JournalManager.Member(account.name, encryptedKey!!)
|
||||||
journalManager.addMember(journal, member)
|
journalManager.addMember(journal, member)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.password(new_key)
|
settings.password(new_key)
|
||||||
App.log.info("Finished uploading changes. Encryption password changed successfully.")
|
Logger.log.info("Finished uploading changes. Encryption password changed successfully.")
|
||||||
|
|
||||||
uiThread {
|
uiThread {
|
||||||
progress.dismiss()
|
progress.dismiss()
|
||||||
|
@ -23,15 +23,16 @@ import android.os.Bundle
|
|||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import android.provider.CalendarContract
|
import android.provider.CalendarContract
|
||||||
import android.provider.ContactsContract
|
import android.provider.ContactsContract
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import at.bitfire.vcard4android.ContactsStorageException
|
import at.bitfire.vcard4android.ContactsStorageException
|
||||||
import com.etesync.syncadapter.*
|
import com.etesync.syncadapter.*
|
||||||
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
||||||
import com.etesync.syncadapter.journalmanager.Exceptions.HttpException
|
import com.etesync.syncadapter.journalmanager.Exceptions.HttpException
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
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
|
||||||
@ -41,7 +42,6 @@ import org.acra.ACRA
|
|||||||
import org.apache.commons.lang3.exception.ExceptionUtils
|
import org.apache.commons.lang3.exception.ExceptionUtils
|
||||||
import org.apache.commons.lang3.text.WordUtils
|
import org.apache.commons.lang3.text.WordUtils
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
|
||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
|
|
||||||
class DebugInfoActivity : BaseActivity(), LoaderManager.LoaderCallbacks<String> {
|
class DebugInfoActivity : BaseActivity(), LoaderManager.LoaderCallbacks<String> {
|
||||||
@ -144,7 +144,7 @@ class DebugInfoActivity : BaseActivity(), LoaderManager.LoaderCallbacks<String>
|
|||||||
report.append("\nSOFTWARE INFORMATION\n" + "EteSync version: ").append(BuildConfig.VERSION_NAME).append(" (").append(BuildConfig.VERSION_CODE).append(") ").append("\n")
|
report.append("\nSOFTWARE INFORMATION\n" + "EteSync version: ").append(BuildConfig.VERSION_NAME).append(" (").append(BuildConfig.VERSION_CODE).append(") ").append("\n")
|
||||||
.append("Installed from: ").append(installedFrom).append("\n")
|
.append("Installed from: ").append(installedFrom).append("\n")
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
App.log.log(Level.SEVERE, "Couldn't get software information", ex)
|
Logger.log.log(Level.SEVERE, "Couldn't get software information", ex)
|
||||||
}
|
}
|
||||||
|
|
||||||
report.append("CONFIGURATION\n")
|
report.append("CONFIGURATION\n")
|
||||||
@ -216,7 +216,7 @@ class DebugInfoActivity : BaseActivity(), LoaderManager.LoaderCallbacks<String>
|
|||||||
"SYSTEM INFORMATION\n" + "Android version: ").append(Build.VERSION.RELEASE).append(" (").append(Build.DISPLAY).append(")\n" + "Device: ").append(WordUtils.capitalize(Build.MANUFACTURER)).append(" ").append(Build.MODEL).append(" (").append(Build.DEVICE).append(")\n\n"
|
"SYSTEM INFORMATION\n" + "Android version: ").append(Build.VERSION.RELEASE).append(" (").append(Build.DISPLAY).append(")\n" + "Device: ").append(WordUtils.capitalize(Build.MANUFACTURER)).append(" ").append(Build.MODEL).append(" (").append(Build.DEVICE).append(")\n\n"
|
||||||
)
|
)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
App.log.log(Level.SEVERE, "Couldn't get system details", ex)
|
Logger.log.log(Level.SEVERE, "Couldn't get system details", ex)
|
||||||
}
|
}
|
||||||
|
|
||||||
report.append("--- END DEBUG INFO ---\n")
|
report.append("--- END DEBUG INFO ---\n")
|
||||||
|
@ -8,7 +8,7 @@ import android.provider.CalendarContract
|
|||||||
import android.provider.CalendarContract.Calendars
|
import android.provider.CalendarContract.Calendars
|
||||||
import android.provider.CalendarContract.Events
|
import android.provider.CalendarContract.Events
|
||||||
import android.provider.ContactsContract
|
import android.provider.ContactsContract
|
||||||
import com.etesync.syncadapter.App
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.resource.LocalCalendar
|
import com.etesync.syncadapter.resource.LocalCalendar
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ class CalendarAccount protected constructor(val account: Account) {
|
|||||||
CAL_COLS, null, null,
|
CAL_COLS, null, null,
|
||||||
ContactsContract.RawContacts.ACCOUNT_NAME + " ASC, " + ContactsContract.RawContacts.ACCOUNT_TYPE)
|
ContactsContract.RawContacts.ACCOUNT_NAME + " ASC, " + ContactsContract.RawContacts.ACCOUNT_TYPE)
|
||||||
} catch (except: Exception) {
|
} catch (except: Exception) {
|
||||||
App.log.warning("Calendar provider is missing columns, continuing anyway")
|
Logger.log.warning("Calendar provider is missing columns, continuing anyway")
|
||||||
cur = resolver.query(Calendars.CONTENT_URI, null, null, null, null)
|
cur = resolver.query(Calendars.CONTENT_URI, null, null, null, null)
|
||||||
except.printStackTrace()
|
except.printStackTrace()
|
||||||
}
|
}
|
||||||
|
@ -20,10 +20,10 @@ import at.bitfire.ical4android.InvalidCalendarException
|
|||||||
import at.bitfire.vcard4android.BatchOperation
|
import at.bitfire.vcard4android.BatchOperation
|
||||||
import at.bitfire.vcard4android.Contact
|
import at.bitfire.vcard4android.Contact
|
||||||
import at.bitfire.vcard4android.ContactsStorageException
|
import at.bitfire.vcard4android.ContactsStorageException
|
||||||
import com.etesync.syncadapter.App
|
|
||||||
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
||||||
import com.etesync.syncadapter.Constants.KEY_COLLECTION_INFO
|
import com.etesync.syncadapter.Constants.KEY_COLLECTION_INFO
|
||||||
import com.etesync.syncadapter.R
|
import com.etesync.syncadapter.R
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.model.CollectionInfo
|
import com.etesync.syncadapter.model.CollectionInfo
|
||||||
import com.etesync.syncadapter.resource.*
|
import com.etesync.syncadapter.resource.*
|
||||||
import com.etesync.syncadapter.syncadapter.ContactsSyncManager
|
import com.etesync.syncadapter.syncadapter.ContactsSyncManager
|
||||||
@ -144,13 +144,13 @@ class ImportFragment : DialogFragment() {
|
|||||||
if (data != null) {
|
if (data != null) {
|
||||||
// Get the URI of the selected file
|
// Get the URI of the selected file
|
||||||
val uri = data.data!!
|
val uri = data.data!!
|
||||||
App.log.info("Importing uri = ${uri}")
|
Logger.log.info("Importing uri = ${uri}")
|
||||||
try {
|
try {
|
||||||
inputStream = activity!!.contentResolver.openInputStream(uri)
|
inputStream = activity!!.contentResolver.openInputStream(uri)
|
||||||
|
|
||||||
Thread(ImportEntriesLoader()).start()
|
Thread(ImportEntriesLoader()).start()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
App.log.severe("File select error: ${e.message}")
|
Logger.log.severe("File select error: ${e.message}")
|
||||||
|
|
||||||
val importResult = ImportResult()
|
val importResult = ImportResult()
|
||||||
importResult.e = e
|
importResult.e = e
|
||||||
@ -218,7 +218,7 @@ class ImportFragment : DialogFragment() {
|
|||||||
importReader.close()
|
importReader.close()
|
||||||
|
|
||||||
if (events.size == 0) {
|
if (events.size == 0) {
|
||||||
App.log.warning("Empty/invalid file.")
|
Logger.log.warning("Empty/invalid file.")
|
||||||
result.e = Exception("Empty/invalid file.")
|
result.e = Exception("Empty/invalid file.")
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -235,11 +235,11 @@ class ImportFragment : DialogFragment() {
|
|||||||
throw FileNotFoundException("Failed to load local resource.")
|
throw FileNotFoundException("Failed to load local resource.")
|
||||||
}
|
}
|
||||||
} catch (e: CalendarStorageException) {
|
} catch (e: CalendarStorageException) {
|
||||||
App.log.info("Fail" + e.localizedMessage)
|
Logger.log.info("Fail" + e.localizedMessage)
|
||||||
result.e = e
|
result.e = e
|
||||||
return result
|
return result
|
||||||
} catch (e: FileNotFoundException) {
|
} catch (e: FileNotFoundException) {
|
||||||
App.log.info("Fail" + e.localizedMessage)
|
Logger.log.info("Fail" + e.localizedMessage)
|
||||||
result.e = e
|
result.e = e
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -261,7 +261,7 @@ class ImportFragment : DialogFragment() {
|
|||||||
val contacts = Contact.fromReader(importReader, downloader)
|
val contacts = Contact.fromReader(importReader, downloader)
|
||||||
|
|
||||||
if (contacts.size == 0) {
|
if (contacts.size == 0) {
|
||||||
App.log.warning("Empty/invalid file.")
|
Logger.log.warning("Empty/invalid file.")
|
||||||
result.e = Exception("Empty/invalid file.")
|
result.e = Exception("Empty/invalid file.")
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -13,13 +13,13 @@ import android.app.ProgressDialog
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.loader.app.LoaderManager
|
import androidx.loader.app.LoaderManager
|
||||||
import androidx.loader.content.AsyncTaskLoader
|
import androidx.loader.content.AsyncTaskLoader
|
||||||
import androidx.loader.content.Loader
|
import androidx.loader.content.Loader
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import com.etesync.syncadapter.App
|
|
||||||
import com.etesync.syncadapter.R
|
import com.etesync.syncadapter.R
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.ui.DebugInfoActivity
|
import com.etesync.syncadapter.ui.DebugInfoActivity
|
||||||
import com.etesync.syncadapter.ui.setup.BaseConfigurationFinder.Configuration
|
import com.etesync.syncadapter.ui.setup.BaseConfigurationFinder.Configuration
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ class DetectConfigurationFragment : DialogFragment(), LoaderManager.LoaderCallba
|
|||||||
.addToBackStack(null)
|
.addToBackStack(null)
|
||||||
.commitAllowingStateLoss()
|
.commitAllowingStateLoss()
|
||||||
} else
|
} else
|
||||||
App.log.severe("Configuration detection failed")
|
Logger.log.severe("Configuration detection failed")
|
||||||
|
|
||||||
dismissAllowingStateLoss()
|
dismissAllowingStateLoss()
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,8 @@ package com.etesync.syncadapter.ui.setup
|
|||||||
|
|
||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
|
||||||
import com.etesync.syncadapter.App
|
|
||||||
import com.etesync.syncadapter.Constants
|
import com.etesync.syncadapter.Constants
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.net.URISyntaxException
|
import java.net.URISyntaxException
|
||||||
|
|
||||||
@ -27,7 +25,7 @@ class LoginCredentials(_uri: URI?, val userName: String, val password: String) :
|
|||||||
try {
|
try {
|
||||||
uri = URI(Constants.serviceUrl.toString())
|
uri = URI(Constants.serviceUrl.toString())
|
||||||
} catch (e: URISyntaxException) {
|
} catch (e: URISyntaxException) {
|
||||||
App.log.severe("Should never happen, it's a constant")
|
Logger.log.severe("Should never happen, it's a constant")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,15 +14,15 @@ import android.app.ProgressDialog
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.loader.app.LoaderManager
|
import androidx.loader.app.LoaderManager
|
||||||
import androidx.loader.content.AsyncTaskLoader
|
import androidx.loader.content.AsyncTaskLoader
|
||||||
import androidx.loader.content.Loader
|
import androidx.loader.content.Loader
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import com.etesync.syncadapter.AccountSettings
|
import com.etesync.syncadapter.AccountSettings
|
||||||
import com.etesync.syncadapter.App
|
|
||||||
import com.etesync.syncadapter.InvalidAccountException
|
import com.etesync.syncadapter.InvalidAccountException
|
||||||
import com.etesync.syncadapter.R
|
import com.etesync.syncadapter.R
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.ui.DebugInfoActivity
|
import com.etesync.syncadapter.ui.DebugInfoActivity
|
||||||
import com.etesync.syncadapter.ui.setup.BaseConfigurationFinder.Configuration
|
import com.etesync.syncadapter.ui.setup.BaseConfigurationFinder.Configuration
|
||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
@ -64,7 +64,7 @@ class LoginCredentialsChangeFragment : DialogFragment(), LoaderManager.LoaderCal
|
|||||||
try {
|
try {
|
||||||
settings = AccountSettings(activity!!, account)
|
settings = AccountSettings(activity!!, account)
|
||||||
} catch (e: InvalidAccountException) {
|
} catch (e: InvalidAccountException) {
|
||||||
App.log.log(Level.INFO, "Account is invalid or doesn't exist (anymore)", e)
|
Logger.log.log(Level.INFO, "Account is invalid or doesn't exist (anymore)", e)
|
||||||
activity!!.finish()
|
activity!!.finish()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ class LoginCredentialsChangeFragment : DialogFragment(), LoaderManager.LoaderCal
|
|||||||
settings.authToken = data.authtoken!!
|
settings.authToken = data.authtoken!!
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
App.log.severe("Configuration detection failed")
|
Logger.log.severe("Configuration detection failed")
|
||||||
|
|
||||||
dismissAllowingStateLoss()
|
dismissAllowingStateLoss()
|
||||||
}
|
}
|
||||||
|
@ -18,13 +18,14 @@ import android.content.Context
|
|||||||
import android.os.AsyncTask
|
import android.os.AsyncTask
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.CalendarContract
|
import android.provider.CalendarContract
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
import at.bitfire.ical4android.TaskProvider
|
import at.bitfire.ical4android.TaskProvider
|
||||||
import com.etesync.syncadapter.*
|
import com.etesync.syncadapter.*
|
||||||
import com.etesync.syncadapter.journalmanager.Crypto
|
import com.etesync.syncadapter.journalmanager.Crypto
|
||||||
import com.etesync.syncadapter.journalmanager.Exceptions
|
import com.etesync.syncadapter.journalmanager.Exceptions
|
||||||
import com.etesync.syncadapter.journalmanager.UserInfoManager
|
import com.etesync.syncadapter.journalmanager.UserInfoManager
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
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.ServiceEntity
|
import com.etesync.syncadapter.model.ServiceEntity
|
||||||
@ -56,7 +57,7 @@ class SetupEncryptionFragment : DialogFragment() {
|
|||||||
|
|
||||||
override fun onPostExecute(result: Configuration) {
|
override fun onPostExecute(result: Configuration) {
|
||||||
if (config.error != null && config.error is Exceptions.IntegrityException) {
|
if (config.error != null && config.error is Exceptions.IntegrityException) {
|
||||||
App.log.severe("Wrong encryption password.")
|
Logger.log.severe("Wrong encryption password.")
|
||||||
AlertDialog.Builder(activity!!)
|
AlertDialog.Builder(activity!!)
|
||||||
.setTitle(R.string.wrong_encryption_password)
|
.setTitle(R.string.wrong_encryption_password)
|
||||||
.setIcon(R.drawable.ic_error_dark)
|
.setIcon(R.drawable.ic_error_dark)
|
||||||
@ -71,7 +72,7 @@ class SetupEncryptionFragment : DialogFragment() {
|
|||||||
activity!!.finish()
|
activity!!.finish()
|
||||||
}
|
}
|
||||||
} catch (e: InvalidAccountException) {
|
} catch (e: InvalidAccountException) {
|
||||||
App.log.severe("Account creation failed!")
|
Logger.log.severe("Account creation failed!")
|
||||||
AlertDialog.Builder(activity!!)
|
AlertDialog.Builder(activity!!)
|
||||||
.setTitle(R.string.account_creation_failed)
|
.setTitle(R.string.account_creation_failed)
|
||||||
.setIcon(R.drawable.ic_error_dark)
|
.setIcon(R.drawable.ic_error_dark)
|
||||||
@ -87,9 +88,9 @@ class SetupEncryptionFragment : DialogFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun doInBackground(vararg aVoids: Void): Configuration {
|
override fun doInBackground(vararg aVoids: Void): Configuration {
|
||||||
App.log.info("Started deriving key")
|
Logger.log.info("Started deriving key")
|
||||||
config.password = Crypto.deriveKey(config.userName, config.rawPassword!!)
|
config.password = Crypto.deriveKey(config.userName, config.rawPassword!!)
|
||||||
App.log.info("Finished deriving key")
|
Logger.log.info("Finished deriving key")
|
||||||
config.error = null
|
config.error = null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -99,7 +100,7 @@ class SetupEncryptionFragment : DialogFragment() {
|
|||||||
val userInfoManager = UserInfoManager(httpClient, HttpUrl.get(config.url)!!)
|
val userInfoManager = UserInfoManager(httpClient, HttpUrl.get(config.url)!!)
|
||||||
val userInfo = userInfoManager.fetch(config.userName)
|
val userInfo = userInfoManager.fetch(config.userName)
|
||||||
if (userInfo != null) {
|
if (userInfo != null) {
|
||||||
App.log.info("Fetched userInfo for " + config.userName)
|
Logger.log.info("Fetched userInfo for " + config.userName)
|
||||||
cryptoManager = Crypto.CryptoManager(userInfo.version!!.toInt(), config.password!!, "userInfo")
|
cryptoManager = Crypto.CryptoManager(userInfo.version!!.toInt(), config.password!!, "userInfo")
|
||||||
userInfo.verify(cryptoManager)
|
userInfo.verify(cryptoManager)
|
||||||
config.keyPair = Crypto.AsymmetricKeyPair(userInfo.getContent(cryptoManager)!!, userInfo.pubkey!!)
|
config.keyPair = Crypto.AsymmetricKeyPair(userInfo.getContent(cryptoManager)!!, userInfo.pubkey!!)
|
||||||
@ -119,7 +120,7 @@ class SetupEncryptionFragment : DialogFragment() {
|
|||||||
val account = Account(accountName, App.accountType)
|
val account = Account(accountName, App.accountType)
|
||||||
|
|
||||||
// create Android account
|
// create Android account
|
||||||
App.log.log(Level.INFO, "Creating Android account with initial config", arrayOf(account, config.userName, config.url))
|
Logger.log.log(Level.INFO, "Creating Android account with initial config", arrayOf(account, config.userName, config.url))
|
||||||
|
|
||||||
val accountManager = AccountManager.get(context)
|
val accountManager = AccountManager.get(context)
|
||||||
if (!accountManager.addAccountExplicitly(account, config.password, null))
|
if (!accountManager.addAccountExplicitly(account, config.password, null))
|
||||||
@ -128,7 +129,7 @@ class SetupEncryptionFragment : DialogFragment() {
|
|||||||
AccountSettings.setUserData(accountManager, account, config.url, config.userName)
|
AccountSettings.setUserData(accountManager, account, config.url, config.userName)
|
||||||
|
|
||||||
// add entries for account to service DB
|
// add entries for account to service DB
|
||||||
App.log.log(Level.INFO, "Writing account configuration to database", config)
|
Logger.log.log(Level.INFO, "Writing account configuration to database", config)
|
||||||
try {
|
try {
|
||||||
val settings = AccountSettings(context!!, account)
|
val settings = AccountSettings(context!!, account)
|
||||||
|
|
||||||
@ -165,7 +166,7 @@ class SetupEncryptionFragment : DialogFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (e: InvalidAccountException) {
|
} catch (e: InvalidAccountException) {
|
||||||
App.log.log(Level.SEVERE, "Couldn't access account settings", e)
|
Logger.log.log(Level.SEVERE, "Couldn't access account settings", e)
|
||||||
AndroidCompat.removeAccount(accountManager, account)
|
AndroidCompat.removeAccount(accountManager, account)
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
|
@ -6,13 +6,17 @@ import android.app.ProgressDialog
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.AsyncTask
|
import android.os.AsyncTask
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.fragment.app.DialogFragment
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import com.etesync.syncadapter.*
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import com.etesync.syncadapter.AccountSettings
|
||||||
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
||||||
|
import com.etesync.syncadapter.HttpClient
|
||||||
|
import com.etesync.syncadapter.InvalidAccountException
|
||||||
|
import com.etesync.syncadapter.R
|
||||||
import com.etesync.syncadapter.journalmanager.Constants
|
import com.etesync.syncadapter.journalmanager.Constants
|
||||||
import com.etesync.syncadapter.journalmanager.Crypto
|
import com.etesync.syncadapter.journalmanager.Crypto
|
||||||
import com.etesync.syncadapter.journalmanager.UserInfoManager
|
import com.etesync.syncadapter.journalmanager.UserInfoManager
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
|
|
||||||
class SetupUserInfoFragment : DialogFragment() {
|
class SetupUserInfoFragment : DialogFragment() {
|
||||||
@ -53,12 +57,12 @@ class SetupUserInfoFragment : DialogFragment() {
|
|||||||
var userInfo: UserInfoManager.UserInfo? = userInfoManager.fetch(account.name)
|
var userInfo: UserInfoManager.UserInfo? = userInfoManager.fetch(account.name)
|
||||||
|
|
||||||
if (userInfo == null) {
|
if (userInfo == null) {
|
||||||
App.log.info("Creating userInfo for " + account.name)
|
Logger.log.info("Creating userInfo for " + account.name)
|
||||||
cryptoManager = Crypto.CryptoManager(Constants.CURRENT_VERSION, settings.password(), "userInfo")
|
cryptoManager = Crypto.CryptoManager(Constants.CURRENT_VERSION, settings.password(), "userInfo")
|
||||||
userInfo = UserInfoManager.UserInfo.generate(cryptoManager, account.name)
|
userInfo = UserInfoManager.UserInfo.generate(cryptoManager, account.name)
|
||||||
userInfoManager.create(userInfo)
|
userInfoManager.create(userInfo)
|
||||||
} else {
|
} else {
|
||||||
App.log.info("Fetched userInfo for " + account.name)
|
Logger.log.info("Fetched userInfo for " + account.name)
|
||||||
cryptoManager = Crypto.CryptoManager(userInfo.version!!.toInt(), settings.password(), "userInfo")
|
cryptoManager = Crypto.CryptoManager(userInfo.version!!.toInt(), settings.password(), "userInfo")
|
||||||
userInfo.verify(cryptoManager)
|
userInfo.verify(cryptoManager)
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,10 @@ package com.etesync.syncadapter.utils
|
|||||||
import android.accounts.Account
|
import android.accounts.Account
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import at.bitfire.ical4android.Event
|
import at.bitfire.ical4android.Event
|
||||||
import com.etesync.syncadapter.App
|
|
||||||
import com.etesync.syncadapter.R
|
import com.etesync.syncadapter.R
|
||||||
|
import com.etesync.syncadapter.log.Logger
|
||||||
import net.fortuna.ical4j.model.property.Attendee
|
import net.fortuna.ical4j.model.property.Attendee
|
||||||
import org.acra.attachment.AcraContentProvider
|
import org.acra.attachment.AcraContentProvider
|
||||||
import org.acra.util.IOUtils
|
import org.acra.util.IOUtils
|
||||||
@ -38,7 +37,7 @@ class EventEmailInvitation constructor(val context: Context, val account: Accoun
|
|||||||
formatAttendees(event.attendees)))
|
formatAttendees(event.attendees)))
|
||||||
val uri = createAttachmentFromString(context, icsContent)
|
val uri = createAttachmentFromString(context, icsContent)
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
App.log.severe("Unable to create attachment from calendar event")
|
Logger.log.severe("Unable to create attachment from calendar event")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
Loading…
Reference in New Issue
Block a user