mirror of
https://github.com/bitfireAT/davx5-ose
synced 2024-10-06 19:34:23 +00:00
Don't listen for account changes all the time (#780)
* Delete account: don't rely on cleanup worker * Don't list for account changes all the time
This commit is contained in:
parent
1ad8e892b6
commit
952cb52b95
|
@ -9,22 +9,22 @@ import android.os.StrictMode
|
|||
import androidx.hilt.work.HiltWorkerFactory
|
||||
import androidx.work.Configuration
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.syncadapter.AccountsUpdatedListener
|
||||
import at.bitfire.davdroid.syncadapter.AccountsCleanupWorker
|
||||
import at.bitfire.davdroid.ui.DebugInfoActivity
|
||||
import at.bitfire.davdroid.ui.NotificationUtils
|
||||
import at.bitfire.davdroid.ui.UiUtils
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.logging.Level
|
||||
import javax.inject.Inject
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
@HiltAndroidApp
|
||||
class App: Application(), Thread.UncaughtExceptionHandler, Configuration.Provider {
|
||||
|
||||
@Inject lateinit var accountsUpdatedListener: AccountsUpdatedListener
|
||||
@Inject lateinit var workerFactory: HiltWorkerFactory
|
||||
|
||||
override val workManagerConfiguration: Configuration
|
||||
|
@ -58,15 +58,15 @@ class App: Application(), Thread.UncaughtExceptionHandler, Configuration.Provide
|
|||
|
||||
// don't block UI for some background checks
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
thread {
|
||||
// watch for account changes/deletions
|
||||
accountsUpdatedListener.listen()
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
// clean up orphaned accounts in DB from time to time
|
||||
AccountsCleanupWorker.enqueue(this@App)
|
||||
|
||||
// watch installed/removed tasks apps over whole app lifetime and update sync settings accordingly
|
||||
TasksAppWatcher.watchInstalledTaskApps(this, GlobalScope)
|
||||
TasksAppWatcher.watchInstalledTaskApps(this@App, this)
|
||||
|
||||
// create/update app shortcuts
|
||||
UiUtils.updateShortcuts(this)
|
||||
UiUtils.updateShortcuts(this@App)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,9 @@ interface ServiceDao {
|
|||
@Query("DELETE FROM service")
|
||||
fun deleteAll()
|
||||
|
||||
@Query("DELETE FROM service WHERE accountName=:accountName")
|
||||
suspend fun deleteByAccount(accountName: String)
|
||||
|
||||
@Query("DELETE FROM service WHERE accountName NOT IN (:accountNames)")
|
||||
fun deleteExceptAccounts(accountNames: Array<String>)
|
||||
|
||||
|
|
|
@ -142,6 +142,13 @@ class AccountRepository @Inject constructor(
|
|||
// blocks calling thread
|
||||
future.result
|
||||
}
|
||||
|
||||
// delete address book accounts
|
||||
LocalAddressBook.deleteByAccount(context, accountName)
|
||||
|
||||
// delete from database
|
||||
serviceRepository.deleteByAccount(accountName)
|
||||
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
Logger.log.log(Level.WARNING, "Couldn't remove account $accountName", e)
|
||||
|
@ -232,7 +239,7 @@ class AccountRepository @Inject constructor(
|
|||
}
|
||||
|
||||
// update account name references in database
|
||||
serviceRepository.onAccountRenamed(oldName, newName)
|
||||
serviceRepository.renameAccount(oldName, newName)
|
||||
|
||||
// update main account of address book accounts
|
||||
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED)
|
||||
|
|
|
@ -9,18 +9,22 @@ import at.bitfire.davdroid.db.Service
|
|||
import javax.inject.Inject
|
||||
|
||||
class DavServiceRepository @Inject constructor(
|
||||
private val db: AppDatabase
|
||||
db: AppDatabase
|
||||
) {
|
||||
|
||||
private val dao = db.serviceDao()
|
||||
|
||||
suspend fun deleteByAccount(accountName: String) {
|
||||
dao.deleteByAccount(accountName)
|
||||
}
|
||||
|
||||
fun getCalDavServiceFlow(accountName: String) =
|
||||
dao.getByAccountAndTypeFlow(accountName, Service.TYPE_CALDAV)
|
||||
|
||||
fun getCardDavServiceFlow(accountName: String) =
|
||||
dao.getByAccountAndTypeFlow(accountName, Service.TYPE_CARDDAV)
|
||||
|
||||
suspend fun onAccountRenamed(oldName: String, newName: String) {
|
||||
suspend fun renameAccount(oldName: String, newName: String) {
|
||||
dao.renameAccount(oldName, newName)
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ import at.bitfire.davdroid.db.SyncState
|
|||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.settings.AccountSettings
|
||||
import at.bitfire.davdroid.syncadapter.AccountUtils
|
||||
import at.bitfire.davdroid.util.DavUtils
|
||||
import at.bitfire.davdroid.util.lastSegment
|
||||
import at.bitfire.davdroid.util.setAndVerifyUserData
|
||||
import at.bitfire.vcard4android.AndroidAddressBook
|
||||
|
@ -84,6 +83,13 @@ open class LocalAddressBook(
|
|||
return addressBook
|
||||
}
|
||||
|
||||
fun deleteByAccount(context: Context, accountName: String) {
|
||||
val mainAccount = Account(accountName, context.getString(R.string.account_type))
|
||||
findAll(context, null, mainAccount).forEach {
|
||||
it.delete()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and returns all the local address books belonging to a given main account
|
||||
*
|
||||
|
|
|
@ -8,8 +8,8 @@ import android.accounts.Account
|
|||
import android.accounts.AccountManager
|
||||
import android.content.Context
|
||||
import androidx.hilt.work.HiltWorker
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
|
@ -19,8 +19,8 @@ import at.bitfire.davdroid.log.Logger
|
|||
import at.bitfire.davdroid.resource.LocalAddressBook
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import java.time.Duration
|
||||
import java.util.concurrent.Semaphore
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.logging.Level
|
||||
|
||||
@HiltWorker
|
||||
|
@ -42,12 +42,15 @@ class AccountsCleanupWorker @AssistedInject constructor(
|
|||
/** Must be called exactly one time after calling `lockAccountsCleanup`. */
|
||||
fun unlockAccountsCleanup() = mutex.release()
|
||||
|
||||
/**
|
||||
* Enqueues [AccountsCleanupWorker] to be run regularly (but not necessarily now).
|
||||
*/
|
||||
fun enqueue(context: Context) {
|
||||
WorkManager.getInstance(context).enqueueUniqueWork(NAME, ExistingWorkPolicy.KEEP,
|
||||
OneTimeWorkRequestBuilder<AccountsCleanupWorker>()
|
||||
.setInitialDelay(15, TimeUnit.SECONDS) // wait some time before cleaning up accouts
|
||||
.build())
|
||||
// run every day
|
||||
val rq = PeriodicWorkRequestBuilder<AccountsCleanupWorker>(Duration.ofDays(1))
|
||||
WorkManager.getInstance(context).enqueueUniquePeriodicWork(NAME, ExistingPeriodicWorkPolicy.UPDATE, rq.build())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun doWork(): Result {
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
|
||||
*/
|
||||
|
||||
package at.bitfire.davdroid.syncadapter
|
||||
|
||||
import android.accounts.Account
|
||||
import android.accounts.AccountManager
|
||||
import android.accounts.OnAccountsUpdateListener
|
||||
import android.content.Context
|
||||
import androidx.annotation.AnyThread
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
class AccountsUpdatedListener private constructor(
|
||||
val context: Context
|
||||
): OnAccountsUpdateListener {
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object AccountsUpdatedListenerModule {
|
||||
@Provides
|
||||
@Singleton
|
||||
fun accountsUpdatedListener(@ApplicationContext context: Context) = AccountsUpdatedListener(context)
|
||||
}
|
||||
|
||||
fun listen() {
|
||||
val accountManager = AccountManager.get(context)
|
||||
accountManager.addOnAccountsUpdatedListener(this, null, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the system accounts have been updated. The interesting case for us is when
|
||||
* a DAVx5 account has been removed. Then we enqueue an [AccountsCleanupWorker] to remove
|
||||
* the orphaned entries from the database.
|
||||
*/
|
||||
@AnyThread
|
||||
override fun onAccountsUpdated(accounts: Array<out Account>) {
|
||||
AccountsCleanupWorker.enqueue(context)
|
||||
}
|
||||
|
||||
}
|
|
@ -13,7 +13,6 @@ import androidx.compose.runtime.setValue
|
|||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.asFlow
|
||||
import androidx.lifecycle.switchMap
|
||||
import androidx.lifecycle.viewModelScope
|
||||
|
@ -31,7 +30,9 @@ import dagger.assisted.Assisted
|
|||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
@ -135,9 +136,11 @@ class AccountScreenModel @AssistedInject constructor(
|
|||
|
||||
// actions
|
||||
|
||||
private val notInterruptibleScope = CoroutineScope(SupervisorJob())
|
||||
|
||||
/** Deletes the account from the system (won't touch collections on the server). */
|
||||
fun deleteAccount() {
|
||||
viewModelScope.launch {
|
||||
notInterruptibleScope.launch {
|
||||
accountRepository.delete(account.name)
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +160,7 @@ class AccountScreenModel @AssistedInject constructor(
|
|||
* @param newName new account name
|
||||
*/
|
||||
fun renameAccount(newName: String) {
|
||||
viewModelScope.launch {
|
||||
notInterruptibleScope.launch {
|
||||
try {
|
||||
accountRepository.rename(account.name, newName)
|
||||
|
||||
|
|
Loading…
Reference in a new issue