diff options
author | Ricki Hirner <hirner@bitfire.at> | 2022-10-12 18:29:23 +0300 |
---|---|---|
committer | Ricki Hirner <hirner@bitfire.at> | 2022-10-12 18:35:12 +0300 |
commit | d2614bd87e7af3daa8fa1ae9e1bad90e3d2d58c3 (patch) | |
tree | 7f5311297f7fa29ed2a2940f0799ec8f1bcd8e0c | |
parent | e14460111e9020189b69ece5c433c6386285b44c (diff) |
Create an option to pre-select the read-only setting for address books (bitfireAT/davx5#141)
* [WIP] add managed restriction to force read-only addressbooks
* Honor app-wide read-only address book setting when syncing address books
* reflect status of force read-only address books setting in the GUI
Co-authored-by: Sunik Kupfer <kupfer@bitfire.at>
6 files changed, 69 insertions, 11 deletions
diff --git a/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.kt b/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.kt index eba09f81..c49a1cbd 100644 --- a/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.kt +++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.kt @@ -46,7 +46,16 @@ open class LocalAddressBook( const val USER_DATA_URL = "url" const val USER_DATA_READ_ONLY = "read_only" - fun create(context: Context, provider: ContentProviderClient, mainAccount: Account, info: Collection): LocalAddressBook { + /** + * Creates a local address book. + * + * @param context app context to resolve string resources + * @param provider contacts provider client + * @param mainAccount main account this address book (account) belongs to + * @param info collection where to take the name and settings from + * @param forceReadOnly `true`: set the address book to "force read-only"; `false`: determine read-only flag from [info] + */ + fun create(context: Context, provider: ContentProviderClient, mainAccount: Account, info: Collection, forceReadOnly: Boolean): LocalAddressBook { val account = Account(accountName(mainAccount, info), context.getString(R.string.account_type_address_book)) val userData = initialUserData(mainAccount, info.url.toString()) Logger.log.log(Level.INFO, "Creating local address book $account", userData) @@ -61,7 +70,7 @@ open class LocalAddressBook( values.put(ContactsContract.Settings.SHOULD_SYNC, 1) values.put(ContactsContract.Settings.UNGROUPED_VISIBLE, 1) addressBook.settings = values - addressBook.readOnly = !info.privWriteContent || info.forceReadOnly + addressBook.readOnly = forceReadOnly || !info.privWriteContent || info.forceReadOnly return addressBook } @@ -199,7 +208,13 @@ open class LocalAddressBook( return number } - fun update(info: Collection) { + /** + * Updates the address book settings. + * + * @param info collection where to take the settings from + * @param forceReadOnly `true`: set the address book to "force read-only"; `false`: determine read-only flag from [info] + */ + fun update(info: Collection, forceReadOnly: Boolean) { val newAccountName = accountName(mainAccount, info) if (account.name != newAccountName && Build.VERSION.SDK_INT >= 21) { @@ -209,7 +224,7 @@ open class LocalAddressBook( account = future.result } - val nowReadOnly = !info.privWriteContent || info.forceReadOnly + val nowReadOnly = forceReadOnly || !info.privWriteContent || info.forceReadOnly if (nowReadOnly != readOnly) { Constants.log.info("Address book now read-only = $nowReadOnly, updating contacts") diff --git a/app/src/main/java/at/bitfire/davdroid/settings/DefaultsProvider.kt b/app/src/main/java/at/bitfire/davdroid/settings/DefaultsProvider.kt index 3390bba5..9484d41a 100644 --- a/app/src/main/java/at/bitfire/davdroid/settings/DefaultsProvider.kt +++ b/app/src/main/java/at/bitfire/davdroid/settings/DefaultsProvider.kt @@ -26,7 +26,8 @@ class DefaultsProvider( override val booleanDefaults = mutableMapOf( Pair(Settings.DISTRUST_SYSTEM_CERTIFICATES, false), - Pair(Settings.SYNC_ALL_COLLECTIONS, false) + Pair(Settings.SYNC_ALL_COLLECTIONS, false), + Pair(Settings.FORCE_READ_ONLY_ADDRESSBOOKS, false) ) override val intDefaults = mapOf( diff --git a/app/src/main/java/at/bitfire/davdroid/settings/Settings.kt b/app/src/main/java/at/bitfire/davdroid/settings/Settings.kt index 67599ded..31d058fc 100644 --- a/app/src/main/java/at/bitfire/davdroid/settings/Settings.kt +++ b/app/src/main/java/at/bitfire/davdroid/settings/Settings.kt @@ -38,5 +38,8 @@ object Settings { /** whether detected collections are selected for synchronization for default */ const val SYNC_ALL_COLLECTIONS = "sync_all_collections" + + /** whether all address books are forced to be read-only */ + const val FORCE_READ_ONLY_ADDRESSBOOKS = "force_read_only_addressbooks" } diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/AddressBooksSyncAdapterService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/AddressBooksSyncAdapterService.kt index 275ab782..fed850c1 100644 --- a/app/src/main/java/at/bitfire/davdroid/syncadapter/AddressBooksSyncAdapterService.kt +++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/AddressBooksSyncAdapterService.kt @@ -21,6 +21,12 @@ import at.bitfire.davdroid.db.Service import at.bitfire.davdroid.log.Logger import at.bitfire.davdroid.resource.LocalAddressBook import at.bitfire.davdroid.settings.AccountSettings +import at.bitfire.davdroid.settings.Settings +import at.bitfire.davdroid.settings.SettingsManager +import dagger.hilt.EntryPoint +import dagger.hilt.InstallIn +import dagger.hilt.android.EntryPointAccessors +import dagger.hilt.components.SingletonComponent import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl import java.util.logging.Level @@ -35,6 +41,15 @@ class AddressBooksSyncAdapterService : SyncAdapterService() { appDatabase: AppDatabase ) : SyncAdapter(context, appDatabase) { + @EntryPoint + @InstallIn(SingletonComponent::class) + interface AddressBooksSyncAdapterEntryPoint { + fun settingsManager(): SettingsManager + } + + val entryPoint = EntryPointAccessors.fromApplication(context, AddressBooksSyncAdapterEntryPoint::class.java) + val settingsManager = entryPoint.settingsManager() + override fun sync(account: Account, extras: Bundle, authority: String, httpClient: Lazy<HttpClient>, provider: ContentProviderClient, syncResult: SyncResult) { try { val accountSettings = AccountSettings(context, account) @@ -85,6 +100,8 @@ class AddressBooksSyncAdapterService : SyncAdapterService() { return false } + val forceAllReadOnly = settingsManager.getBoolean(Settings.FORCE_READ_ONLY_ADDRESSBOOKS) + // delete/update local address books for (addressBook in LocalAddressBook.findAll(context, contactsProvider, account)) { val url = addressBook.url.toHttpUrl() @@ -96,7 +113,7 @@ class AddressBooksSyncAdapterService : SyncAdapterService() { // remote CollectionInfo found for this local collection, update data try { Logger.log.log(Level.FINE, "Updating local address book $url", info) - addressBook.update(info) + addressBook.update(info, forceAllReadOnly) } catch (e: Exception) { Logger.log.log(Level.WARNING, "Couldn't rename address book account", e) } @@ -108,7 +125,7 @@ class AddressBooksSyncAdapterService : SyncAdapterService() { // create new local address books for ((_, info) in remoteAddressBooks) { Logger.log.log(Level.INFO, "Adding local address book", info) - LocalAddressBook.create(context, contactsProvider, account, info) + LocalAddressBook.create(context, contactsProvider, account, info, forceAllReadOnly) } } finally { contactsProvider?.closeCompat() diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/AddressBooksFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/AddressBooksFragment.kt index 4a8e2da8..ff5e8741 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/account/AddressBooksFragment.kt +++ b/app/src/main/java/at/bitfire/davdroid/ui/account/AddressBooksFragment.kt @@ -11,6 +11,12 @@ import at.bitfire.davdroid.PermissionUtils import at.bitfire.davdroid.R import at.bitfire.davdroid.databinding.AccountCarddavItemBinding import at.bitfire.davdroid.db.Collection +import at.bitfire.davdroid.settings.Settings +import at.bitfire.davdroid.settings.SettingsManager +import dagger.hilt.EntryPoint +import dagger.hilt.InstallIn +import dagger.hilt.android.EntryPointAccessors +import dagger.hilt.components.SingletonComponent class AddressBooksFragment: CollectionsFragment() { @@ -53,9 +59,18 @@ class AddressBooksFragment: CollectionsFragment() { class AddressBookViewHolder( parent: ViewGroup, accountModel: AccountActivity.Model, - val fragmentManager: FragmentManager + val fragmentManager: FragmentManager, ): CollectionViewHolder<AccountCarddavItemBinding>(parent, AccountCarddavItemBinding.inflate(LayoutInflater.from(parent.context), parent, false), accountModel) { + @EntryPoint + @InstallIn(SingletonComponent::class) + interface AddressBookViewHolderEntryPoint { + fun settingsManager(): SettingsManager + } + + private val settings = EntryPointAccessors.fromApplication(parent.context, AddressBookViewHolderEntryPoint::class.java).settingsManager() + private val forceReadOnlyAddressBooks = settings.getBoolean(Settings.FORCE_READ_ONLY_ADDRESSBOOKS) // managed restriction + override fun bindTo(item: Collection) { binding.sync.isChecked = item.sync binding.title.text = item.title() @@ -67,12 +82,12 @@ class AddressBooksFragment: CollectionsFragment() { binding.description.visibility = View.VISIBLE } - binding.readOnly.visibility = if (item.readOnly()) View.VISIBLE else View.GONE + binding.readOnly.visibility = if (item.readOnly() || forceReadOnlyAddressBooks) View.VISIBLE else View.GONE itemView.setOnClickListener { accountModel.toggleSync(item) } - binding.actionOverflow.setOnClickListener(CollectionPopupListener(accountModel, item, fragmentManager)) + binding.actionOverflow.setOnClickListener(CollectionPopupListener(accountModel, item, fragmentManager, forceReadOnlyAddressBooks)) } } diff --git a/app/src/main/java/at/bitfire/davdroid/ui/account/CollectionsFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/account/CollectionsFragment.kt index f4e197b4..b379497a 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/account/CollectionsFragment.kt +++ b/app/src/main/java/at/bitfire/davdroid/ui/account/CollectionsFragment.kt @@ -226,7 +226,8 @@ abstract class CollectionsFragment: Fragment(), SwipeRefreshLayout.OnRefreshList class CollectionPopupListener( private val accountModel: AccountActivity.Model, private val item: Collection, - private val fragmentManager: FragmentManager + private val fragmentManager: FragmentManager, + private val forceReadOnly: Boolean = false ): View.OnClickListener { override fun onClick(anchor: View) { @@ -244,6 +245,12 @@ abstract class CollectionsFragment: Fragment(), SwipeRefreshLayout.OnRefreshList else isVisible = false } + + if (item.type == Collection.TYPE_ADDRESSBOOK && forceReadOnly) { + // managed restriction "force read-only address books" is active + isChecked = true + isEnabled = false + } } popup.menu.findItem(R.id.delete_collection).isVisible = item.privUnbind |