Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit bd7d6c7b authored by Ricki Hirner's avatar Ricki Hirner
Browse files

AccountSettings: handle address book accounts (#101)

* AccountSettings: handle address book accounts (fixes: address books are not synced because of IllegalArgumentException)

* Tests (not finished)
parent 0e93a47d
Loading
Loading
Loading
Loading
+0 −12
Original line number Diff line number Diff line
@@ -11,18 +11,6 @@

    <application>

        <service
            android:name=".syncadapter.AddressBookAuthenticatorService"
            android:exported="false">
            <intent-filter>
                <action android:name="android.accounts.AccountAuthenticator"/>
            </intent-filter>

            <meta-data
                android:name="android.accounts.AccountAuthenticator"
                android:resource="@xml/test_account_authenticator"/>
        </service>

    </application>

</manifest>
+77 −0
Original line number Diff line number Diff line
/***************************************************************************************************
 * Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
 **************************************************************************************************/

package at.bitfire.davdroid.resource

import android.accounts.Account
import android.accounts.AccountManager
import androidx.test.platform.app.InstrumentationRegistry
import at.bitfire.davdroid.R
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test

@HiltAndroidTest
class LocalAddressBookTest {

    @get:Rule()
    val hiltRule = HiltAndroidRule(this)

    val context = InstrumentationRegistry.getInstrumentation().targetContext

    val mainAccountType = context.getString(R.string.account_type)
    val mainAccount = Account("main", mainAccountType)

    val addressBookAccountType = context.getString(R.string.account_type_address_book)
    val addressBookAccount = Account("sub", addressBookAccountType)

    val accountManager = AccountManager.get(context)

    @Before
    fun setUp() {
        hiltRule.inject()

        // TODO DOES NOT WORK: the account immediately starts to sync, which creates the sync adapter services.
        // The services however can't be created because Hilt is "not ready" (although it has been initialized in the line above).
        // assertTrue(AccountUtils.createAccount(context, mainAccount, AccountSettings.initialUserData(null)))
    }

    @After
    fun cleanup() {
        accountManager.removeAccount(addressBookAccount, null, null)
        accountManager.removeAccount(mainAccount, null, null)
    }


    // TODO see above
    /*@Test
    fun testMainAccount_AddressBookAccount_WithMainAccount() {
        // create address book account
        assertTrue(accountManager.addAccountExplicitly(addressBookAccount, null, Bundle().apply {
            putString(LocalAddressBook.USER_DATA_MAIN_ACCOUNT_NAME, mainAccount.name)
            putString(LocalAddressBook.USER_DATA_MAIN_ACCOUNT_TYPE, mainAccount.type)
        }))

        // check mainAccount()
        assertEquals(mainAccount, LocalAddressBook.mainAccount(context, addressBookAccount))
    }

    @Test(expected = IllegalArgumentException::class)
    fun testMainAccount_AddressBookAccount_WithoutMainAccount() {
        // create address book account
        assertTrue(accountManager.addAccountExplicitly(addressBookAccount, null, Bundle()))

        // check mainAccount(); should fail because there's no main account
        LocalAddressBook.mainAccount(context, addressBookAccount)
    }*/

    @Test(expected = IllegalArgumentException::class)
    fun testMainAccount_OtherAccount() {
        LocalAddressBook.mainAccount(context, Account("Other Account", "com.example"))
    }

}
 No newline at end of file
+1 −2
Original line number Diff line number Diff line
@@ -232,8 +232,7 @@
            android:authorities="@string/address_books_authority"
            android:exported="false"
            android:label="@string/address_books_authority_title"
            android:name=".syncadapter.AddressBookProvider"
            android:multiprocess="false"/>
            android:name=".syncadapter.AddressBookProvider" />
        <service
            android:name=".syncadapter.AddressBooksSyncAdapterService"
            android:exported="true"
+14 −17
Original line number Diff line number Diff line
@@ -104,12 +104,13 @@ open class LocalAddressBook(
        fun mainAccount(context: Context, account: Account): Account =
            if (account.type == context.getString(R.string.account_type_address_book)) {
                val manager = AccountManager.get(context)
                    Account(
                            manager.getUserData(account, USER_DATA_MAIN_ACCOUNT_NAME),
                            manager.getUserData(account, USER_DATA_MAIN_ACCOUNT_TYPE)
                    )
                val accountName = manager.getUserData(account, USER_DATA_MAIN_ACCOUNT_NAME)
                val accountType = manager.getUserData(account, USER_DATA_MAIN_ACCOUNT_TYPE)
                if (accountName == null || accountType == null)
                    throw IllegalArgumentException("Address book account does not have a main account")
                Account(accountName, accountType)
            } else
                    account
                throw IllegalArgumentException("Account is not an address book account")

    }

@@ -135,20 +136,16 @@ open class LocalAddressBook(
    private var _mainAccount: Account? = null
    /**
     * The associated main account which this address book accounts belongs to.
     * @throws IllegalStateException when no main account is assigned
     *
     * @throws IllegalArgumentException when [account] is not an address book account or when no main account is assigned
     */
    open var mainAccount: Account
        get() {
            _mainAccount?.let { return it }

            AccountManager.get(context).let { accountManager ->
                val name = accountManager.getUserData(account, USER_DATA_MAIN_ACCOUNT_NAME)
                val type = accountManager.getUserData(account, USER_DATA_MAIN_ACCOUNT_TYPE)
                if (name != null && type != null)
                    return Account(name, type)
                else
                    throw IllegalStateException("No main account assigned to address book account")
            }
            val result = mainAccount(context, account)
            _mainAccount = result
            return result
        }
        set(newMainAccount) {
            AccountManager.get(context).let { accountManager ->
+20 −1
Original line number Diff line number Diff line
@@ -57,12 +57,17 @@ import java.util.logging.Level
/**
 * Manages settings of an account.
 *
 * @param context       Required to access account settings
 * @param argAccount    Account to take settings from. If this account is an address book account,
 * settings will be taken from the corresponding main account instead.
 *
 * @throws InvalidAccountException on construction when the account doesn't exist (anymore)
 * @throws IllegalArgumentException when the account type is not _DAVx5_ or _DAVx5 address book_
 */
@Suppress("FunctionName")
class AccountSettings(
    val context: Context,
    val account: Account
    argAccount: Account
) {

    @EntryPoint
@@ -191,8 +196,22 @@ class AccountSettings(
    val settings = EntryPointAccessors.fromApplication(context, AccountSettingsEntryPoint::class.java).settingsManager()

    val accountManager: AccountManager = AccountManager.get(context)
    val account: Account

    init {
        when (argAccount.type) {
            context.getString(R.string.account_type_address_book) -> {
                /* argAccount is an address book account, which is not a main account. However settings are
                   stored in the main account, so resolve and use the main account instead. */
                account = LocalAddressBook.mainAccount(context, argAccount)
            }
            context.getString(R.string.account_type) ->
                account = argAccount
            else ->
                throw IllegalArgumentException("Account type not supported")
        }

        // synchronize because account migration must only be run one time
        synchronized(AccountSettings::class.java) {
            val versionStr = accountManager.getUserData(account, KEY_SETTINGS_VERSION) ?: throw InvalidAccountException(account)
            var version = 0
Loading