1
0
mirror of https://github.com/etesync/android synced 2024-12-23 07:08:16 +00:00

Account Loader: use view models instead of AsyncTask.

Should fix rare crashes some users were experiencing.
This commit is contained in:
Tom Hacohen 2020-11-02 16:59:44 +02:00
parent c4c897ee95
commit eb09c3a0e0

View File

@ -10,7 +10,6 @@ package com.etesync.syncadapter.ui
import android.accounts.Account import android.accounts.Account
import android.accounts.AccountManager import android.accounts.AccountManager
import android.app.LoaderManager
import android.content.* import android.content.*
import android.content.ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE import android.content.ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE
import android.net.Uri import android.net.Uri
@ -22,9 +21,14 @@ import android.provider.ContactsContract
import android.text.TextUtils import android.text.TextUtils
import android.view.* import android.view.*
import android.widget.* import android.widget.*
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.observe
import at.bitfire.ical4android.TaskProvider.Companion.TASK_PROVIDERS import at.bitfire.ical4android.TaskProvider.Companion.TASK_PROVIDERS
import at.bitfire.vcard4android.ContactsStorageException import at.bitfire.vcard4android.ContactsStorageException
import com.etebase.client.CollectionAccessLevel import com.etebase.client.CollectionAccessLevel
@ -54,10 +58,12 @@ import com.google.android.material.snackbar.Snackbar
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.acra.ACRA import org.acra.ACRA
import org.jetbrains.anko.doAsync import org.jetbrains.anko.doAsync
import org.jetbrains.anko.uiThread
import tourguide.tourguide.ToolTip import tourguide.tourguide.ToolTip
import java.util.logging.Level import java.util.logging.Level
class AccountActivity : BaseActivity(), Toolbar.OnMenuItemClickListener, PopupMenu.OnMenuItemClickListener, LoaderManager.LoaderCallbacks<AccountActivity.AccountInfo>, Refreshable { class AccountActivity : BaseActivity(), Toolbar.OnMenuItemClickListener, PopupMenu.OnMenuItemClickListener, Refreshable {
private val model: AccountInfoViewModel by viewModels()
private lateinit var account: Account private lateinit var account: Account
private lateinit var settings: AccountSettings private lateinit var settings: AccountSettings
@ -143,7 +149,13 @@ class AccountActivity : BaseActivity(), Toolbar.OnMenuItemClickListener, PopupMe
} }
// load CardDAV/CalDAV journals // load CardDAV/CalDAV journals
loaderManager.initLoader(0, intent.extras, this) if (savedInstanceState == null) {
model.initialize(this, account)
model.loadAccount()
model.observe(this) {
updateUi(it)
}
}
if (!HintManager.getHintSeen(this, HINT_VIEW_COLLECTION)) { if (!HintManager.getHintSeen(this, HINT_VIEW_COLLECTION)) {
ShowcaseBuilder.getBuilder(this) ShowcaseBuilder.getBuilder(this)
@ -281,15 +293,11 @@ class AccountActivity : BaseActivity(), Toolbar.OnMenuItemClickListener, PopupMe
} }
} }
override fun onCreateLoader(id: Int, args: Bundle?): Loader<AccountInfo> {
return AccountLoader(this, account)
}
override fun refresh() { override fun refresh() {
loaderManager.restartLoader(0, intent.extras, this) model.loadAccount()
} }
override fun onLoadFinished(loader: Loader<AccountInfo>, info: AccountInfo) { fun updateUi(info: AccountInfo) {
accountInfo = info accountInfo = info
if (info.carddav != null) { if (info.carddav != null) {
@ -340,41 +348,47 @@ class AccountActivity : BaseActivity(), Toolbar.OnMenuItemClickListener, PopupMe
} }
} }
override fun onLoaderReset(loader: Loader<AccountInfo>) {
if (listCardDAV != null)
listCardDAV!!.adapter = null
if (listCalDAV != null) class AccountInfoViewModel : ViewModel(), AccountUpdateService.RefreshingStatusListener, ServiceConnection, SyncStatusObserver {
listCalDAV!!.adapter = null private val holder = MutableLiveData<AccountActivity.AccountInfo>()
private lateinit var context: Context
if (listTaskDAV != null) private lateinit var account: Account
listTaskDAV!!.adapter = null
}
private class AccountLoader(context: Context, private val account: Account) : AsyncTaskLoader<AccountInfo>(context), AccountUpdateService.RefreshingStatusListener, ServiceConnection, SyncStatusObserver {
private var davService: AccountUpdateService.InfoBinder? = null private var davService: AccountUpdateService.InfoBinder? = null
private var syncStatusListener: Any? = null private var syncStatusListener: Any? = null
override fun onStartLoading() { fun initialize(context: Context, account: Account) {
this.context = context
this.account = account
syncStatusListener = ContentResolver.addStatusChangeListener(SYNC_OBSERVER_TYPE_ACTIVE, this) syncStatusListener = ContentResolver.addStatusChangeListener(SYNC_OBSERVER_TYPE_ACTIVE, this)
context.bindService(Intent(context, AccountUpdateService::class.java), this, Context.BIND_AUTO_CREATE) context.bindService(Intent(context, AccountUpdateService::class.java), this, Context.BIND_AUTO_CREATE)
} }
override fun onStopLoading() { fun loadAccount() {
doAsync {
val info = doLoad()
uiThread {
holder.value = info
}
}
}
override fun onCleared() {
davService?.removeRefreshingStatusListener(this) davService?.removeRefreshingStatusListener(this)
context.unbindService(this) context.unbindService(this)
if (syncStatusListener != null) if (syncStatusListener != null) {
ContentResolver.removeStatusChangeListener(syncStatusListener) ContentResolver.removeStatusChangeListener(syncStatusListener)
syncStatusListener = null
}
} }
override fun onServiceConnected(name: ComponentName, service: IBinder) { override fun onServiceConnected(name: ComponentName, service: IBinder) {
davService = service as AccountUpdateService.InfoBinder davService = service as AccountUpdateService.InfoBinder
davService!!.addRefreshingStatusListener(this, false) davService!!.addRefreshingStatusListener(this, false)
forceLoad() loadAccount()
} }
override fun onServiceDisconnected(name: ComponentName) { override fun onServiceDisconnected(name: ComponentName) {
@ -382,18 +396,19 @@ class AccountActivity : BaseActivity(), Toolbar.OnMenuItemClickListener, PopupMe
} }
override fun onDavRefreshStatusChanged(id: Long, refreshing: Boolean) { override fun onDavRefreshStatusChanged(id: Long, refreshing: Boolean) {
forceLoad() loadAccount()
} }
override fun onStatusChanged(which: Int) { override fun onStatusChanged(which: Int) {
forceLoad() loadAccount()
} }
private fun getLegacyJournals(data: MyEntityDataStore, serviceEntity: ServiceEntity): List<CollectionListItemInfo> { private fun getLegacyJournals(data: MyEntityDataStore, serviceEntity: ServiceEntity): List<CollectionListItemInfo> {
return JournalEntity.getJournals(data, serviceEntity).map { return JournalEntity.getJournals(data, serviceEntity).map {
val info = it.info val info = it.info
val isAdmin = it.isOwner(account.name) val isAdmin = it.isOwner(account.name)
CollectionListItemInfo(it.uid, info.enumType!!, info.displayName!!, info.description ?: "", info.color, it.isReadOnly, isAdmin, info) CollectionListItemInfo(it.uid, info.enumType!!, info.displayName!!, info.description
?: "", info.color, it.isReadOnly, isAdmin, info)
} }
} }
@ -425,8 +440,8 @@ class AccountActivity : BaseActivity(), Toolbar.OnMenuItemClickListener, PopupMe
} }
} }
override fun loadInBackground(): AccountInfo { private fun doLoad(): AccountActivity.AccountInfo {
val info = AccountInfo() val info = AccountActivity.AccountInfo()
val settings: AccountSettings val settings: AccountSettings
try { try {
settings = AccountSettings(context, account) settings = AccountSettings(context, account)
@ -442,7 +457,7 @@ class AccountActivity : BaseActivity(), Toolbar.OnMenuItemClickListener, PopupMe
when (service) { when (service) {
CollectionInfo.Type.ADDRESS_BOOK -> { CollectionInfo.Type.ADDRESS_BOOK -> {
info.carddav = AccountInfo.ServiceInfo() info.carddav = AccountInfo.ServiceInfo()
info.carddav!!.refreshing = davService != null && davService!!.isRefreshing(id) || ContentResolver.isSyncActive(account, App.addressBooksAuthority) info.carddav!!.refreshing = ContentResolver.isSyncActive(account, App.addressBooksAuthority)
info.carddav!!.infos = getLegacyJournals(data, serviceEntity) info.carddav!!.infos = getLegacyJournals(data, serviceEntity)
val accountManager = AccountManager.get(context) val accountManager = AccountManager.get(context)
@ -458,16 +473,14 @@ class AccountActivity : BaseActivity(), Toolbar.OnMenuItemClickListener, PopupMe
} }
CollectionInfo.Type.CALENDAR -> { CollectionInfo.Type.CALENDAR -> {
info.caldav = AccountInfo.ServiceInfo() info.caldav = AccountInfo.ServiceInfo()
info.caldav!!.refreshing = davService != null && davService!!.isRefreshing(id) || info.caldav!!.refreshing = ContentResolver.isSyncActive(account, CalendarContract.AUTHORITY)
ContentResolver.isSyncActive(account, CalendarContract.AUTHORITY)
info.caldav!!.infos = getLegacyJournals(data, serviceEntity) info.caldav!!.infos = getLegacyJournals(data, serviceEntity)
} }
CollectionInfo.Type.TASKS -> { CollectionInfo.Type.TASKS -> {
info.taskdav = AccountInfo.ServiceInfo() info.taskdav = AccountInfo.ServiceInfo()
info.taskdav!!.refreshing = davService != null && davService!!.isRefreshing(id) || info.taskdav!!.refreshing = TASK_PROVIDERS.any {
TASK_PROVIDERS.any { ContentResolver.isSyncActive(account, it.authority)
ContentResolver.isSyncActive(account, it.authority) }
}
info.taskdav!!.infos = getLegacyJournals(data, serviceEntity) info.taskdav!!.infos = getLegacyJournals(data, serviceEntity)
} }
} }
@ -507,6 +520,12 @@ class AccountActivity : BaseActivity(), Toolbar.OnMenuItemClickListener, PopupMe
return info return info
} }
fun observe(owner: LifecycleOwner, observer: (AccountActivity.AccountInfo) -> Unit) =
holder.observe(owner, observer)
val value: AccountActivity.AccountInfo?
get() = holder.value
} }
@ -616,4 +635,4 @@ class AccountActivity : BaseActivity(), Toolbar.OnMenuItemClickListener, PopupMe
private val HINT_VIEW_COLLECTION = "ViewCollection" private val HINT_VIEW_COLLECTION = "ViewCollection"
} }
} }