mirror of
https://github.com/etesync/android
synced 2024-11-25 17:38:13 +00:00
Don't rely on the ACCOUNTS_CHANGED broadcast receiver
I've seen some crashes there. This change brings it inline with DAVDroid, and looks cleaner regardless. Based on 1f7298f947a4878e86fcba0c6722e34b03cb63c6 from DAVDroid
This commit is contained in:
parent
f629d23c38
commit
3b0bfbb054
@ -164,12 +164,6 @@
|
||||
android:enabled="true">
|
||||
</service>
|
||||
|
||||
<receiver android:name=".AccountsChangedReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".PackageChangedReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PACKAGE_ADDED"/>
|
||||
|
@ -35,7 +35,6 @@ class AccountUpdateService : Service() {
|
||||
val action = intent.action
|
||||
|
||||
when (action) {
|
||||
ACTION_ACCOUNTS_UPDATED -> cleanupAccounts()
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,45 +76,4 @@ class AccountUpdateService : Service() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ACTION RUNNABLES
|
||||
which actually do the work
|
||||
*/
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
internal fun cleanupAccounts() {
|
||||
Logger.log.info("Cleaning up orphaned accounts")
|
||||
|
||||
val accountNames = LinkedList<String>()
|
||||
val am = AccountManager.get(this)
|
||||
for (account in am.getAccountsByType(getString(R.string.account_type))) {
|
||||
accountNames.add(account.name)
|
||||
}
|
||||
|
||||
val data = (application as App).data
|
||||
|
||||
// delete orphaned address book accounts
|
||||
for (addrBookAccount in am.getAccountsByType(getString(R.string.account_type_address_book))) {
|
||||
val addressBook = LocalAddressBook(this, addrBookAccount, null)
|
||||
try {
|
||||
if (!accountNames.contains(addressBook.mainAccount.name))
|
||||
addressBook.delete()
|
||||
} catch (e: ContactsStorageException) {
|
||||
Logger.log.log(Level.SEVERE, "Couldn't get address book main account", e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (accountNames.isEmpty()) {
|
||||
data.delete(ServiceEntity::class.java).get().value()
|
||||
} else {
|
||||
data.delete(ServiceEntity::class.java).where(ServiceEntity.ACCOUNT.notIn(accountNames)).get().value()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val ACTION_ACCOUNTS_UPDATED = "accountsUpdated"
|
||||
}
|
||||
}
|
||||
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the GNU Public License v3.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*/
|
||||
|
||||
package com.etesync.syncadapter
|
||||
|
||||
import android.accounts.AccountManager
|
||||
import android.accounts.OnAccountsUpdateListener
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.etesync.syncadapter.log.Logger
|
||||
import java.util.*
|
||||
|
||||
class AccountsChangedReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION == intent.action) {
|
||||
val serviceIntent = Intent(context, AccountUpdateService::class.java)
|
||||
serviceIntent.action = AccountUpdateService.ACTION_ACCOUNTS_UPDATED
|
||||
try {
|
||||
context.startService(serviceIntent)
|
||||
} catch (e: IllegalStateException) {
|
||||
Logger.log.warning("Got an illegal state exception! Ignoring...")
|
||||
}
|
||||
|
||||
for (listener in listeners)
|
||||
listener.onAccountsUpdated(null)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
protected val listeners: MutableList<OnAccountsUpdateListener> = LinkedList()
|
||||
|
||||
fun registerListener(listener: OnAccountsUpdateListener, callImmediately: Boolean) {
|
||||
listeners.add(listener)
|
||||
if (callImmediately)
|
||||
listener.onAccountsUpdated(null)
|
||||
}
|
||||
|
||||
fun unregisterListener(listener: OnAccountsUpdateListener) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2013 – 2015 Ricki Hirner (bitfire web engineering).
|
||||
* Copyright © Ricki Hirner (bitfire web engineering).
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the GNU Public License v3.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@ -8,65 +8,110 @@
|
||||
package com.etesync.syncadapter.syncadapter
|
||||
|
||||
import android.accounts.*
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.database.DatabaseUtils
|
||||
import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import at.bitfire.vcard4android.ContactsStorageException
|
||||
import com.etesync.syncadapter.App
|
||||
import com.etesync.syncadapter.R
|
||||
import com.etesync.syncadapter.log.Logger
|
||||
import com.etesync.syncadapter.model.ServiceDB
|
||||
import com.etesync.syncadapter.model.ServiceEntity
|
||||
import com.etesync.syncadapter.resource.LocalAddressBook
|
||||
import com.etesync.syncadapter.ui.setup.LoginActivity
|
||||
import java.util.*
|
||||
import java.util.logging.Level
|
||||
|
||||
|
||||
/**
|
||||
* Account authenticator for the main DAVx5 account type.
|
||||
*
|
||||
* Gets started when a DAVx5 account is removed, too, so it also watches for account removals
|
||||
* and contains the corresponding cleanup code.
|
||||
*/
|
||||
class AccountAuthenticatorService: Service(), OnAccountsUpdateListener {
|
||||
companion object {
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
internal fun cleanupAccounts(context: Context) {
|
||||
Logger.log.info("Cleaning up orphaned accounts")
|
||||
|
||||
val accountNames = LinkedList<String>()
|
||||
val am = AccountManager.get(context)
|
||||
for (account in am.getAccountsByType(context.getString(R.string.account_type))) {
|
||||
accountNames.add(account.name)
|
||||
}
|
||||
|
||||
val data = (context.applicationContext as App).data
|
||||
|
||||
// delete orphaned address book accounts
|
||||
for (addrBookAccount in am.getAccountsByType(context.getString(R.string.account_type_address_book))) {
|
||||
val addressBook = LocalAddressBook(context, addrBookAccount, null)
|
||||
try {
|
||||
if (!accountNames.contains(addressBook.mainAccount.name))
|
||||
addressBook.delete()
|
||||
} catch (e: ContactsStorageException) {
|
||||
Logger.log.log(Level.SEVERE, "Couldn't get address book main account", e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (accountNames.isEmpty()) {
|
||||
data.delete(ServiceEntity::class.java).get().value()
|
||||
} else {
|
||||
data.delete(ServiceEntity::class.java).where(ServiceEntity.ACCOUNT.notIn(accountNames)).get().value()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var accountManager: AccountManager
|
||||
private lateinit var accountAuthenticator: AccountAuthenticator
|
||||
|
||||
class AccountAuthenticatorService : Service() {
|
||||
|
||||
private var accountAuthenticator: AccountAuthenticator? = null
|
||||
|
||||
override fun onCreate() {
|
||||
accountManager = AccountManager.get(this)
|
||||
accountManager.addOnAccountsUpdatedListener(this, null, true)
|
||||
|
||||
accountAuthenticator = AccountAuthenticator(this)
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent): IBinder? {
|
||||
return if (intent.action == android.accounts.AccountManager.ACTION_AUTHENTICATOR_INTENT) accountAuthenticator!!.iBinder else null
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
accountManager.removeOnAccountsUpdatedListener(this)
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?) =
|
||||
accountAuthenticator.iBinder.takeIf { intent?.action == android.accounts.AccountManager.ACTION_AUTHENTICATOR_INTENT }
|
||||
|
||||
|
||||
override fun onAccountsUpdated(accounts: Array<out Account>?) {
|
||||
cleanupAccounts(this)
|
||||
}
|
||||
|
||||
|
||||
private class AccountAuthenticator(internal val context: Context) : AbstractAccountAuthenticator(context) {
|
||||
private class AccountAuthenticator(
|
||||
val context: Context
|
||||
): AbstractAccountAuthenticator(context) {
|
||||
|
||||
@Throws(NetworkErrorException::class)
|
||||
override fun addAccount(response: AccountAuthenticatorResponse, accountType: String, authTokenType: String,
|
||||
requiredFeatures: Array<String>, options: Bundle): Bundle {
|
||||
override fun addAccount(response: AccountAuthenticatorResponse?, accountType: String?, authTokenType: String?, requiredFeatures: Array<String>?, options: Bundle?): Bundle {
|
||||
val intent = Intent(context, LoginActivity::class.java)
|
||||
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response)
|
||||
val bundle = Bundle()
|
||||
val bundle = Bundle(1)
|
||||
bundle.putParcelable(AccountManager.KEY_INTENT, intent)
|
||||
return bundle
|
||||
}
|
||||
|
||||
@Throws(NetworkErrorException::class)
|
||||
override fun confirmCredentials(response: AccountAuthenticatorResponse, account: Account, options: Bundle): Bundle? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun editProperties(response: AccountAuthenticatorResponse, accountType: String): Bundle? {
|
||||
return null
|
||||
}
|
||||
|
||||
@Throws(NetworkErrorException::class)
|
||||
override fun getAuthToken(response: AccountAuthenticatorResponse, account: Account, authTokenType: String, options: Bundle): Bundle? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getAuthTokenLabel(authTokenType: String): String? {
|
||||
return null
|
||||
}
|
||||
|
||||
@Throws(NetworkErrorException::class)
|
||||
override fun hasFeatures(response: AccountAuthenticatorResponse, account: Account, features: Array<String>): Bundle? {
|
||||
return null
|
||||
}
|
||||
|
||||
@Throws(NetworkErrorException::class)
|
||||
override fun updateCredentials(response: AccountAuthenticatorResponse, account: Account, authTokenType: String, options: Bundle): Bundle? {
|
||||
return null
|
||||
}
|
||||
override fun editProperties(response: AccountAuthenticatorResponse?, accountType: String?) = null
|
||||
override fun getAuthTokenLabel(p0: String?) = null
|
||||
override fun confirmCredentials(p0: AccountAuthenticatorResponse?, p1: Account?, p2: Bundle?) = null
|
||||
override fun updateCredentials(p0: AccountAuthenticatorResponse?, p1: Account?, p2: String?, p3: Bundle?) = null
|
||||
override fun getAuthToken(p0: AccountAuthenticatorResponse?, p1: Account?, p2: String?, p3: Bundle?) = null
|
||||
override fun hasFeatures(p0: AccountAuthenticatorResponse?, p1: Account?, p2: Array<out String>?) = null
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -5,75 +5,49 @@
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*/
|
||||
|
||||
package com.etesync.syncadapter.syncadapter
|
||||
|
||||
import android.accounts.*
|
||||
import android.accounts.AbstractAccountAuthenticator
|
||||
import android.accounts.Account
|
||||
import android.accounts.AccountAuthenticatorResponse
|
||||
import android.accounts.AccountManager
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import com.etesync.syncadapter.ui.AccountsActivity
|
||||
|
||||
class NullAuthenticatorService : Service() {
|
||||
class NullAuthenticatorService: Service() {
|
||||
|
||||
private var accountAuthenticator: AccountAuthenticator? = null
|
||||
private lateinit var accountAuthenticator: AccountAuthenticator
|
||||
|
||||
override fun onCreate() {
|
||||
accountAuthenticator = NullAuthenticatorService.AccountAuthenticator(this)
|
||||
accountAuthenticator = AccountAuthenticator(this)
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent): IBinder? {
|
||||
return if (intent.action == android.accounts.AccountManager.ACTION_AUTHENTICATOR_INTENT) accountAuthenticator!!.iBinder else null
|
||||
}
|
||||
override fun onBind(intent: Intent?) =
|
||||
accountAuthenticator.iBinder.takeIf { intent?.action == android.accounts.AccountManager.ACTION_AUTHENTICATOR_INTENT }
|
||||
|
||||
|
||||
private class AccountAuthenticator(internal val context: Context) : AbstractAccountAuthenticator(context) {
|
||||
private class AccountAuthenticator(
|
||||
val context: Context
|
||||
): AbstractAccountAuthenticator(context) {
|
||||
|
||||
override fun editProperties(response: AccountAuthenticatorResponse, accountType: String): Bundle? {
|
||||
return null
|
||||
}
|
||||
|
||||
@Throws(NetworkErrorException::class)
|
||||
override fun addAccount(response: AccountAuthenticatorResponse, accountType: String, authTokenType: String, requiredFeatures: Array<String>, options: Bundle): Bundle {
|
||||
override fun addAccount(response: AccountAuthenticatorResponse?, accountType: String?, authTokenType: String?, requiredFeatures: Array<String>?, options: Bundle?): Bundle {
|
||||
val intent = Intent(context, AccountsActivity::class.java)
|
||||
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response)
|
||||
val bundle = Bundle()
|
||||
val bundle = Bundle(1)
|
||||
bundle.putParcelable(AccountManager.KEY_INTENT, intent)
|
||||
return bundle
|
||||
}
|
||||
|
||||
@Throws(NetworkErrorException::class)
|
||||
override fun confirmCredentials(response: AccountAuthenticatorResponse, account: Account, options: Bundle): Bundle? {
|
||||
return null
|
||||
}
|
||||
override fun editProperties(response: AccountAuthenticatorResponse?, accountType: String?) = null
|
||||
override fun getAuthTokenLabel(p0: String?) = null
|
||||
override fun confirmCredentials(p0: AccountAuthenticatorResponse?, p1: Account?, p2: Bundle?) = null
|
||||
override fun updateCredentials(p0: AccountAuthenticatorResponse?, p1: Account?, p2: String?, p3: Bundle?) = null
|
||||
override fun getAuthToken(p0: AccountAuthenticatorResponse?, p1: Account?, p2: String?, p3: Bundle?) = null
|
||||
override fun hasFeatures(p0: AccountAuthenticatorResponse?, p1: Account?, p2: Array<out String>?) = null
|
||||
|
||||
@Throws(NetworkErrorException::class)
|
||||
override fun getAuthToken(response: AccountAuthenticatorResponse, account: Account, authTokenType: String, options: Bundle): Bundle? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getAuthTokenLabel(authTokenType: String): String? {
|
||||
return null
|
||||
}
|
||||
|
||||
@Throws(NetworkErrorException::class)
|
||||
override fun updateCredentials(response: AccountAuthenticatorResponse, account: Account, authTokenType: String, options: Bundle): Bundle? {
|
||||
return null
|
||||
}
|
||||
|
||||
@Throws(NetworkErrorException::class)
|
||||
override fun hasFeatures(response: AccountAuthenticatorResponse, account: Account, features: Array<String>): Bundle? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getAccountRemovalAllowed(response: AccountAuthenticatorResponse, account: Account): Bundle {
|
||||
val result = Bundle()
|
||||
val allowed = false // we don't want users to explicitly delete inner accounts
|
||||
result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, allowed)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -26,7 +26,6 @@ import android.widget.AbsListView
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.TextView
|
||||
import com.etesync.syncadapter.AccountsChangedReceiver
|
||||
import com.etesync.syncadapter.App
|
||||
import com.etesync.syncadapter.R
|
||||
|
||||
@ -73,19 +72,13 @@ class AccountListFragment : ListFragment(), LoaderManager.LoaderCallbacks<Array<
|
||||
}
|
||||
|
||||
private class AccountLoader(context: Context) : AsyncTaskLoader<Array<Account>>(context), OnAccountsUpdateListener {
|
||||
private val accountManager: AccountManager
|
||||
private val accountManager = AccountManager.get(context)
|
||||
|
||||
init {
|
||||
accountManager = AccountManager.get(context)
|
||||
}
|
||||
override fun onStartLoading() =
|
||||
accountManager.addOnAccountsUpdatedListener(this, null, true)
|
||||
|
||||
override fun onStartLoading() {
|
||||
AccountsChangedReceiver.registerListener(this, true)
|
||||
}
|
||||
|
||||
override fun onStopLoading() {
|
||||
AccountsChangedReceiver.unregisterListener(this)
|
||||
}
|
||||
override fun onStopLoading() =
|
||||
accountManager.removeOnAccountsUpdatedListener(this)
|
||||
|
||||
override fun onAccountsUpdated(accounts: Array<Account>) {
|
||||
forceLoad()
|
||||
|
Loading…
Reference in New Issue
Block a user