Addressbook import: implement group import when importing from account.

Partially fixes #54. Only the from account is currently implemented, but
that should be sufficient for most people already.
pull/61/head
Tom Hacohen 5 years ago
parent c74f9bc23d
commit 0ae278aabd

@ -22,6 +22,7 @@ import at.bitfire.vcard4android.*
import com.etesync.syncadapter.App
import com.etesync.syncadapter.model.CollectionInfo
import com.etesync.syncadapter.model.JournalEntity
import java.io.FileNotFoundException
import java.util.*
import java.util.logging.Level
@ -179,7 +180,14 @@ class LocalAddressBook(
accountManager.removeAccount(account, null, null)
}
override fun findAll(): List<LocalContact> = queryContacts(RawContacts.DELETED + "== 0", null)
override fun findAll(): List<LocalAddress> =
if (includeGroups)
findAllContacts() + findAllGroups()
else
findAllContacts()
fun findAllContacts() = queryContacts("${RawContacts.DELETED}==0", null)
fun findAllGroups() = queryGroups("${Groups.DELETED}==0", null)
/**
* Returns an array of local contacts/groups which have been deleted locally. (DELETED != 0).
@ -259,6 +267,10 @@ class LocalAddressBook(
}
}
fun findGroupById(id: Long): LocalGroup =
queryGroups("${Groups._ID}=?", arrayOf(id.toString())).firstOrNull()
?: throw FileNotFoundException()
override fun count(): Long {
try {
val cursor = provider?.query(syncAdapterURI(RawContacts.CONTENT_URI), null, null, null, null)

@ -47,16 +47,6 @@ class LocalGroup : AndroidGroup, LocalAddress {
val batch = BatchOperation(addressBook.provider)
while (cursor.moveToNext()) {
val id = cursor.getLong(0)
Constants.log.fine("Assigning members to group $id")
// required for workaround for Android 7 which sets DIRTY flag when only meta-data is changed
val changeContactIDs = HashSet<Long>()
// delete all memberships and cached memberships for this group
for (contact in addressBook.getByGroupMembership(id)) {
contact.removeGroupMemberships(batch)
changeContactIDs += contact.id!!
}
// extract list of member UIDs
val members = LinkedList<String>()
@ -71,26 +61,13 @@ class LocalGroup : AndroidGroup, LocalAddress {
}
// insert memberships
for (uid in members) {
val membersIds = members.map {uid ->
Constants.log.fine("Assigning member: $uid")
addressBook.findContactByUID(uid)?.let { member ->
member.addToGroup(batch, id)
changeContactIDs += member.id!!
} ?: Constants.log.warning("Group member not found: $uid")
(addressBook.findByUid(uid) as LocalContact).id!!
}
if (LocalContact.HASH_HACK)
// workaround for Android 7 which sets DIRTY flag when only meta-data is changed
changeContactIDs
.map { addressBook.findContactByID(it) }
.forEach { it.updateHashCode(batch) }
// remove pending memberships
batch.enqueue(BatchOperation.Operation(
ContentProviderOperation.newUpdate(addressBook.syncAdapterURI(ContentUris.withAppendedId(Groups.CONTENT_URI, id)))
.withValue(COLUMN_PENDING_MEMBERS, null)
.withYieldAllowed(true)
))
val group = addressBook.findGroupById(id)
group.setMembers(batch, membersIds)
batch.commit()
}
@ -98,6 +75,8 @@ class LocalGroup : AndroidGroup, LocalAddress {
}
}
private var saveAsDirty = false // When true, the resource will be saved as dirty
override val uuid: String?
get() = fileName
@ -133,6 +112,10 @@ class LocalGroup : AndroidGroup, LocalAddress {
} finally {
members.recycle()
}
if (saveAsDirty) {
values.put(Groups.DIRTY, true)
}
return values
}
@ -187,6 +170,54 @@ class LocalGroup : AndroidGroup, LocalAddress {
addressBook.provider!!.update(groupSyncUri(), values, null, null)
}
private fun setMembers(batch: BatchOperation, members: List<Long>) {
val id = id!!
val addressBook = this.addressBook as LocalAddressBook
Constants.log.fine("Assigning members to group $id")
// required for workaround for Android 7 which sets DIRTY flag when only meta-data is changed
val changeContactIDs = HashSet<Long>()
// delete all memberships and cached memberships for this group
for (contact in addressBook.getByGroupMembership(id)) {
contact.removeGroupMemberships(batch)
changeContactIDs += contact.id!!
}
// insert memberships
for (memberId in members) {
Constants.log.fine("Assigning member: $memberId")
addressBook.findContactByID(memberId).let { member ->
member.addToGroup(batch, id)
changeContactIDs += member.id!!
} ?: Constants.log.warning("Group member not found: $memberId")
}
if (LocalContact.HASH_HACK)
// workaround for Android 7 which sets DIRTY flag when only meta-data is changed
changeContactIDs
.map { addressBook.findContactByID(it) }
.forEach { it.updateHashCode(batch) }
// remove pending memberships
batch.enqueue(BatchOperation.Operation(
ContentProviderOperation.newUpdate(addressBook.syncAdapterURI(ContentUris.withAppendedId(Groups.CONTENT_URI, id)))
.withValue(COLUMN_PENDING_MEMBERS, null)
.withYieldAllowed(true)
))
}
fun createAsDirty(members: List<Long>): Uri {
saveAsDirty = true
val ret = this.add()
val batch = BatchOperation(addressBook.provider!!)
setMembers(batch, members)
batch.commit()
return ret
}
// helpers

@ -26,7 +26,7 @@ class ImportActivity : BaseActivity(), SelectImportMethod, ResultFragment.OnImpo
title = getString(R.string.import_dialog_title)
account = intent.extras!!.getParcelable(EXTRA_ACCOUNT)
account = intent.extras!!.getParcelable(EXTRA_ACCOUNT)!!
info = intent.extras!!.getSerializable(EXTRA_COLLECTION_INFO) as CollectionInfo
if (savedInstanceState == null)

@ -21,13 +21,16 @@ import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import at.bitfire.vcard4android.ContactsStorageException
import com.etesync.syncadapter.App
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
import com.etesync.syncadapter.Constants.KEY_COLLECTION_INFO
import com.etesync.syncadapter.R
import com.etesync.syncadapter.model.CollectionInfo
import com.etesync.syncadapter.resource.LocalAddressBook
import com.etesync.syncadapter.resource.LocalContact
import com.etesync.syncadapter.resource.LocalGroup
import java.util.*
import kotlin.collections.HashMap
class LocalContactImportFragment : Fragment() {
@ -132,9 +135,11 @@ class LocalContactImportFragment : Fragment() {
try {
val addressBook = LocalAddressBook.findByUid(context!!,
context!!.contentResolver.acquireContentProviderClient(ContactsContract.RawContacts.CONTENT_URI)!!,
account, info.uid!!)
val localContacts = localAddressBook.findAll()
val total = localContacts.size
account, info.uid!!)!!
val localContacts = localAddressBook.findAllContacts()
val localGroups = localAddressBook.findAllGroups()
val oldIdToNewId = HashMap<Long, Long>()
val total = localContacts.size + localGroups.size
progressDialog!!.max = total
result.total = total.toLong()
var progress = 0
@ -142,8 +147,27 @@ class LocalContactImportFragment : Fragment() {
val contact = currentLocalContact.contact
try {
val localContact = LocalContact(addressBook!!, contact!!, null, null)
val localContact = LocalContact(addressBook, contact!!, null, null)
localContact.createAsDirty()
oldIdToNewId[currentLocalContact.id!!] = localContact.id!!
result.added++
} catch (e: ContactsStorageException) {
e.printStackTrace()
result.e = e
}
publishProgress(++progress)
}
for (currentLocalGroup in localGroups) {
val group = currentLocalGroup.contact
try {
val localGroup = LocalGroup(addressBook, group!!, null, null)
val members = currentLocalGroup.getMembers().map { it ->
oldIdToNewId[it]!!
}
localGroup.createAsDirty(members)
result.added++
} catch (e: ContactsStorageException) {
e.printStackTrace()

Loading…
Cancel
Save