diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cdae79e680572c3c89cd2027221c54a2ee5217ea..15b95a47f906c290019e7f7635481c95910d4242 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -261,6 +261,21 @@ android:resource="@xml/contacts"/> + + + + + + + + + diff --git a/app/src/main/java/at/bitfire/davdroid/MailAccountSyncHelper.kt b/app/src/main/java/at/bitfire/davdroid/MailAccountSyncHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..daaa68f9bb10ce130e38c0d9137cefa981b58add --- /dev/null +++ b/app/src/main/java/at/bitfire/davdroid/MailAccountSyncHelper.kt @@ -0,0 +1,53 @@ +/* + * Copyright ECORP SAS 2022 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package at.bitfire.davdroid + +import android.content.ComponentName +import android.content.Context +import android.content.Intent + +object MailAccountSyncHelper { + + private const val MAIL_PACKAGE = "foundation.e.mail" + private const val MAIL_RECEIVER_CLASS = "com.fsck.k9.account.AccountSyncReceiver" + private const val ACTION_PREFIX = "foundation.e.accountmanager.account." + + fun accountLoggedIn(applicationContext : Context?) { + val intent = getIntent() + intent.action = ACTION_PREFIX + "create" + applicationContext?.sendBroadcast(intent) + } + + fun accountLoggedOut(applicationContext: Context?, email: String?) { + email?.let { + if (!it.contains("@")) { + return@let + } + val intent = getIntent() + intent.action = ACTION_PREFIX + "remove" + intent.putExtra("account", it) + applicationContext?.sendBroadcast(intent) + } + } + + private fun getIntent() : Intent { + val intent = Intent() + intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) + intent.component = ComponentName(MAIL_PACKAGE, MAIL_RECEIVER_CLASS) + return intent + } +} diff --git a/app/src/main/java/at/bitfire/davdroid/settings/AccountSettings.kt b/app/src/main/java/at/bitfire/davdroid/settings/AccountSettings.kt index f616d0cea1c96e963353e00a3afe0af3884735b5..d3d04cf6680876b4201f41f7e68449b62d372852 100644 --- a/app/src/main/java/at/bitfire/davdroid/settings/AccountSettings.kt +++ b/app/src/main/java/at/bitfire/davdroid/settings/AccountSettings.kt @@ -87,8 +87,9 @@ class AccountSettings( /** Stores the tasks sync interval (in seconds) so that it can be set again when the provider is switched */ const val KEY_SYNC_INTERVAL_TASKS = "sync_interval_tasks" - const val KEY_USERNAME = "user_name" + const val KEY_EMAIL_ADDRESS = "email_address" + const val KEY_AUTH_STATE = "auth_state" const val KEY_CERTIFICATE_ALIAS = "certificate_alias" const val KEY_WIFI_ONLY = "wifi_only" // sync on WiFi only (default: false) @@ -141,6 +142,8 @@ class AccountSettings( if (credentials != null) { if (credentials.userName != null) bundle.putString(KEY_USERNAME, credentials.userName) + bundle.putString(KEY_EMAIL_ADDRESS, credentials.userName) + if (credentials.certificateAlias != null) bundle.putString(KEY_CERTIFICATE_ALIAS, credentials.certificateAlias) } diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/MailSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/MailSyncAdapterService.kt new file mode 100644 index 0000000000000000000000000000000000000000..afaf4c1372c2bd2156f70ba73ed211f2850ccc4f --- /dev/null +++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/MailSyncAdapterService.kt @@ -0,0 +1,39 @@ +/* + * Copyright ECORP SAS 2022 + * 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 + * http://www.gnu.org/licenses/gpl.html + */ + +package at.bitfire.davdroid.syncadapter + +import android.accounts.Account +import android.content.* +import android.os.Bundle +import at.bitfire.davdroid.HttpClient +import at.bitfire.davdroid.db.AppDatabase + +class MailSyncAdapterService : SyncAdapterService() { + + override fun syncAdapter() = MailSyncAdapter(this, appDatabase) + + class MailSyncAdapter( + context: Context, + appDatabase: AppDatabase + ): SyncAdapter(context, appDatabase) { + + override fun sync( + account: Account, + extras: Bundle, + authority: String, + httpClient: Lazy, + provider: ContentProviderClient, + syncResult: SyncResult + ) { + // Unused + } + } + +} diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/AccountActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/AccountActivity.kt index fd4d08c953fee6c17c5db0e3dad7ca1659beec76..daed3cd60c1449a2e8bad67992161e6b16003d84 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/account/AccountActivity.kt +++ b/app/src/main/java/at/bitfire/davdroid/ui/account/AccountActivity.kt @@ -21,8 +21,9 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentStatePagerAdapter import androidx.lifecycle.* import at.bitfire.davdroid.DavUtils -import foundation.e.accountmanager.R - +import at.bitfire.davdroid.MailAccountSyncHelper +import at.bitfire.davdroid.R +import at.bitfire.davdroid.databinding.ActivityAccountBinding import at.bitfire.davdroid.db.AppDatabase import at.bitfire.davdroid.db.Collection import at.bitfire.davdroid.db.Service @@ -126,12 +127,13 @@ class AccountActivity: AppCompatActivity() { private fun deleteAccount() { val accountManager = AccountManager.get(this) - + val email = accountManager.getUserData(model.account, AccountSettings.KEY_EMAIL_ADDRESS) if (Build.VERSION.SDK_INT >= 22) accountManager.removeAccount(model.account, this, { future -> try { if (future.result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) Handler(Looper.getMainLooper()).post { + MailAccountSyncHelper.accountLoggedOut(applicationContext, email) finish() } } catch(e: Exception) { @@ -142,6 +144,7 @@ class AccountActivity: AppCompatActivity() { accountManager.removeAccount(model.account, { future -> try { if (future.result) + MailAccountSyncHelper.accountLoggedOut(applicationContext, email) Handler(Looper.getMainLooper()).post { finish() } diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt index 614ab209ffab66ff815763ed5f860a8e57063e99..193af98b1cecc2b1096777baab9434269bfea5d1 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt +++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt @@ -5,6 +5,7 @@ package at.bitfire.davdroid.ui.setup import android.accounts.Account +import android.accounts.AccountAuthenticatorResponse import android.accounts.AccountManager import android.content.ContentResolver import android.content.Context @@ -22,8 +23,9 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.* import at.bitfire.davdroid.DavService import at.bitfire.davdroid.InvalidAccountException -import foundation.e.accountmanager.R - +import at.bitfire.davdroid.MailAccountSyncHelper +import at.bitfire.davdroid.R +import at.bitfire.davdroid.databinding.LoginAccountDetailsBinding import at.bitfire.davdroid.db.AppDatabase import at.bitfire.davdroid.db.Credentials import at.bitfire.davdroid.db.HomeSet @@ -106,6 +108,7 @@ class AccountDetailsFragment : Fragment() { GroupMethod.valueOf(groupMethodName) ).observe(viewLifecycleOwner, Observer { success -> if (success) { + MailAccountSyncHelper.accountLoggedIn(context?.applicationContext) // close Create account activity requireActivity().finish() // open Account activity for created account @@ -113,9 +116,16 @@ class AccountDetailsFragment : Fragment() { val account = Account(name, getString(R.string.account_type)) intent.putExtra(AccountActivity.EXTRA_ACCOUNT, account) startActivity(intent) + if (activity!!.intent.hasExtra(AccountManager + .KEY_ACCOUNT_AUTHENTICATOR_RESPONSE) && activity!!.intent + .getParcelableExtra(AccountManager + .KEY_ACCOUNT_AUTHENTICATOR_RESPONSE) != null) { + activity!!.intent + .getParcelableExtra(AccountManager + .KEY_ACCOUNT_AUTHENTICATOR_RESPONSE)?.onResult(null) + } } else { Snackbar.make(requireActivity().findViewById(android.R.id.content), R.string.login_account_not_created, Snackbar.LENGTH_LONG).show() - v.createAccountProgress.visibility = View.GONE v.createAccount.visibility = View.VISIBLE } @@ -155,6 +165,7 @@ class AccountDetailsFragment : Fragment() { nameError.value = null } + fun createAccount(name: String, credentials: Credentials?, config: DavResourceFinder.Configuration, groupMethod: GroupMethod): LiveData { val result = MutableLiveData() viewModelScope.launch(Dispatchers.Default + NonCancellable) { @@ -168,6 +179,55 @@ class AccountDetailsFragment : Fragment() { result.postValue(false) return@launch } + val accountManager = AccountManager.get(context) + var accountType = context!!.getString(R.string.account_type) + if (!accountManager.addAccountExplicitly(account, credentials!!.password, userData)) { + if (accountType == context.getString(R.string.google_account_type)) { + for (googleAccount in accountManager.getAccountsByType( + context.getString( + R.string.google_account_type + ) + )) { + if (userData.get(AccountSettings.KEY_EMAIL_ADDRESS) == accountManager + .getUserData(account, AccountSettings.KEY_EMAIL_ADDRESS) + ) { + accountManager.setUserData( + googleAccount, AccountSettings.KEY_AUTH_STATE, + userData.getString(AccountSettings.KEY_AUTH_STATE) + ) + } + } + } + } + if (!credentials.password.isNullOrEmpty()) { + accountManager.setPassword(account, credentials.password) + } + + ContentResolver.setSyncAutomatically( + account, + context.getString(R.string.notes_authority), + true + ) + ContentResolver.setSyncAutomatically( + account, + context.getString(R.string.email_authority), + true + ) + ContentResolver.setSyncAutomatically( + account, + context.getString(R.string.media_authority), + true + ) + ContentResolver.setSyncAutomatically( + account, + context.getString(R.string.app_data_authority), + true + ) + ContentResolver.setSyncAutomatically( + account, + context.getString(R.string.metered_edrive_authority), + true + ) // add entries for account to service DB Logger.log.log(Level.INFO, "Writing account configuration to database", config) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eebfb386f865d68bc96a66fb0005e947fc53a8d5..f93b273dc35a14735737c49c6e79adfcbd1b78b2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -11,6 +11,7 @@ Google bitfire.at.davdroid.google + e.foundation.webdav.eelo at.bitfire.davdroid.address_book /e/ diff --git a/app/src/main/res/xml/eelo_sync_email.xml b/app/src/main/res/xml/eelo_sync_email.xml new file mode 100644 index 0000000000000000000000000000000000000000..1e27619597c9b3569360c22d35d3ab4fad97ba8a --- /dev/null +++ b/app/src/main/res/xml/eelo_sync_email.xml @@ -0,0 +1,15 @@ + + + +