Loading app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.kt +21 −13 Original line number Diff line number Diff line Loading @@ -299,6 +299,27 @@ open class LocalAddressBook( } fun getContactIdsByGroupMembership(groupId: Long): List<Long> { val ids = LinkedList<Long>() provider!!.query(syncAdapterURI(ContactsContract.Data.CONTENT_URI), arrayOf(GroupMembership.RAW_CONTACT_ID), "(${GroupMembership.MIMETYPE}=? AND ${GroupMembership.GROUP_ROW_ID}=?)", arrayOf(GroupMembership.CONTENT_ITEM_TYPE, groupId.toString()), null)?.use { cursor -> while (cursor.moveToNext()) ids += cursor.getLong(0) } return ids } fun getContactUidFromId(contactId: Long): String? { provider!!.query(rawContactsSyncUri(), arrayOf(AndroidContact.COLUMN_UID), "${RawContacts._ID}=?", arrayOf(contactId.toString()), null)?.use { cursor -> if (cursor.moveToNext()) return cursor.getString(0) } return null } /** * Queries all contacts with DIRTY flag and checks whether their data checksum has changed, i.e. * if they're "really dirty" (= data has changed, not only metadata, which is not hashed). Loading Loading @@ -331,19 +352,6 @@ open class LocalAddressBook( return reallyDirty } fun getByGroupMembership(groupID: Long): List<LocalContact> { val ids = HashSet<Long>() provider!!.query(syncAdapterURI(ContactsContract.Data.CONTENT_URI), arrayOf(RawContacts.Data.RAW_CONTACT_ID), "(${GroupMembership.MIMETYPE}=? AND ${GroupMembership.GROUP_ROW_ID}=?)", arrayOf(GroupMembership.CONTENT_ITEM_TYPE, groupID.toString()), null)?.use { cursor -> while (cursor.moveToNext()) ids += cursor.getLong(0) } return ids.map { findContactById(it) } } /* special group operations */ Loading app/src/main/java/at/bitfire/davdroid/resource/LocalContact.kt +5 −10 Original line number Diff line number Diff line Loading @@ -47,12 +47,12 @@ class LocalContact: AndroidContact, LocalAddress { override var flags: Int = 0 constructor(addressBook: LocalAddressBook, values: ContentValues) : super(addressBook, values) constructor(addressBook: LocalAddressBook, values: ContentValues): super(addressBook, values) { flags = values.getAsInteger(COLUMN_FLAGS) ?: 0 } constructor(addressBook: LocalAddressBook, contact: Contact, fileName: String?, eTag: String?, flags: Int) : super(addressBook, contact, fileName, eTag) { this.flags = flags constructor(addressBook: LocalAddressBook, contact: Contact, fileName: String?, eTag: String?, _flags: Int): super(addressBook, contact, fileName, eTag) { flags = _flags } init { Loading @@ -63,11 +63,6 @@ class LocalContact: AndroidContact, LocalAddress { processor.registerBuilderFactory(UnknownPropertiesBuilder.Factory) } override fun initializeFromContentValues(values: ContentValues) { super.initializeFromContentValues(values) flags = values.getAsInteger(COLUMN_FLAGS) ?: 0 } override fun prepareForUpload(): String { var uid: String? = null Loading app/src/main/java/at/bitfire/davdroid/resource/LocalGroup.kt +45 −52 Original line number Diff line number Diff line Loading @@ -43,32 +43,25 @@ class LocalGroup: AndroidGroup, LocalAddress { fun applyPendingMemberships(addressBook: LocalAddressBook) { Logger.log.info("Assigning memberships of contact groups") addressBook.provider!!.query( addressBook.groupsSyncUri(), arrayOf(Groups._ID, Groups.TITLE, COLUMN_PENDING_MEMBERS), "$COLUMN_PENDING_MEMBERS IS NOT NULL", null, null )?.use { cursor -> val batch = BatchOperation(addressBook.provider) while (cursor.moveToNext()) { val groupId = cursor.getLong(0) val groupName = cursor.getString(1) val pendingMemberUids = PendingMemberships.fromString(cursor.getString(2)).uids.toMutableSet() val currentMembers = addressBook.getByGroupMembership(groupId) addressBook.allGroups { group -> val groupId = group.id!! val pendingMemberUids = group.pendingMemberships.toMutableSet() val batch = BatchOperation(addressBook.provider!!) // required for workaround for Android 7 which sets DIRTY flag when only meta-data is changed val changeContactIDs = HashSet<Long>() // process members which are currently in this group, but shouldn't be for (currentMember in currentMembers) { val uid = currentMember.getContact().uid ?: continue for (currentMemberId in addressBook.getContactIdsByGroupMembership(groupId)) { val uid = addressBook.getContactUidFromId(currentMemberId) ?: continue if (!pendingMemberUids.contains(uid)) { Logger.log.fine("$currentMember removed from group $groupName (#$groupId); removing group membership") Logger.log.fine("$currentMemberId removed from group $groupId; removing group membership") val currentMember = addressBook.findContactById(currentMemberId) currentMember.removeGroupMemberships(batch) // Android 7 hack changeContactIDs += currentMember.id!! changeContactIDs += currentMemberId } // UID is processed, remove from pendingMembers Loading @@ -80,11 +73,11 @@ class LocalGroup: AndroidGroup, LocalAddress { for (missingMemberUid in pendingMemberUids) { val missingMember = addressBook.findContactByUid(missingMemberUid) if (missingMember == null) { Logger.log.warning("Group $groupName (#$groupId) has member $missingMemberUid which is not found in the address book; ignoring") Logger.log.warning("Group $groupId has member $missingMemberUid which is not found in the address book; ignoring") continue } Logger.log.fine("Assigning member $missingMember to group $groupName (#$groupId)") Logger.log.fine("Assigning member $missingMember to group $groupId") missingMember.addToGroup(batch, groupId) // Android 7 hack Loading @@ -100,7 +93,6 @@ class LocalGroup: AndroidGroup, LocalAddress { batch.commit() } } } } Loading @@ -111,13 +103,14 @@ class LocalGroup: AndroidGroup, LocalAddress { override var flags: Int = 0 var pendingMemberships = setOf<String>() constructor(addressBook: AndroidAddressBook<out AndroidContact, LocalGroup>, values: ContentValues) : super(addressBook, values) override fun initializeFromContentValues(values: ContentValues) { super.initializeFromContentValues(values) constructor(addressBook: AndroidAddressBook<out AndroidContact, LocalGroup>, values: ContentValues) : super(addressBook, values) { flags = values.getAsInteger(COLUMN_FLAGS) ?: 0 values.getAsString(COLUMN_PENDING_MEMBERS)?.let { members -> pendingMemberships = PendingMemberships.fromString(members).uids } } constructor(addressBook: AndroidAddressBook<out AndroidContact, LocalGroup>, contact: Contact, fileName: String?, eTag: String?, flags: Int) Loading vcard4android @ af41314f Compare 60303f32 to af41314f Original line number Diff line number Diff line Subproject commit 60303f320b756e2865a6b3dea65ebd7a188ca823 Subproject commit af41314f13114f0b2cf9f93e18138cffb24a4d91 Loading
app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.kt +21 −13 Original line number Diff line number Diff line Loading @@ -299,6 +299,27 @@ open class LocalAddressBook( } fun getContactIdsByGroupMembership(groupId: Long): List<Long> { val ids = LinkedList<Long>() provider!!.query(syncAdapterURI(ContactsContract.Data.CONTENT_URI), arrayOf(GroupMembership.RAW_CONTACT_ID), "(${GroupMembership.MIMETYPE}=? AND ${GroupMembership.GROUP_ROW_ID}=?)", arrayOf(GroupMembership.CONTENT_ITEM_TYPE, groupId.toString()), null)?.use { cursor -> while (cursor.moveToNext()) ids += cursor.getLong(0) } return ids } fun getContactUidFromId(contactId: Long): String? { provider!!.query(rawContactsSyncUri(), arrayOf(AndroidContact.COLUMN_UID), "${RawContacts._ID}=?", arrayOf(contactId.toString()), null)?.use { cursor -> if (cursor.moveToNext()) return cursor.getString(0) } return null } /** * Queries all contacts with DIRTY flag and checks whether their data checksum has changed, i.e. * if they're "really dirty" (= data has changed, not only metadata, which is not hashed). Loading Loading @@ -331,19 +352,6 @@ open class LocalAddressBook( return reallyDirty } fun getByGroupMembership(groupID: Long): List<LocalContact> { val ids = HashSet<Long>() provider!!.query(syncAdapterURI(ContactsContract.Data.CONTENT_URI), arrayOf(RawContacts.Data.RAW_CONTACT_ID), "(${GroupMembership.MIMETYPE}=? AND ${GroupMembership.GROUP_ROW_ID}=?)", arrayOf(GroupMembership.CONTENT_ITEM_TYPE, groupID.toString()), null)?.use { cursor -> while (cursor.moveToNext()) ids += cursor.getLong(0) } return ids.map { findContactById(it) } } /* special group operations */ Loading
app/src/main/java/at/bitfire/davdroid/resource/LocalContact.kt +5 −10 Original line number Diff line number Diff line Loading @@ -47,12 +47,12 @@ class LocalContact: AndroidContact, LocalAddress { override var flags: Int = 0 constructor(addressBook: LocalAddressBook, values: ContentValues) : super(addressBook, values) constructor(addressBook: LocalAddressBook, values: ContentValues): super(addressBook, values) { flags = values.getAsInteger(COLUMN_FLAGS) ?: 0 } constructor(addressBook: LocalAddressBook, contact: Contact, fileName: String?, eTag: String?, flags: Int) : super(addressBook, contact, fileName, eTag) { this.flags = flags constructor(addressBook: LocalAddressBook, contact: Contact, fileName: String?, eTag: String?, _flags: Int): super(addressBook, contact, fileName, eTag) { flags = _flags } init { Loading @@ -63,11 +63,6 @@ class LocalContact: AndroidContact, LocalAddress { processor.registerBuilderFactory(UnknownPropertiesBuilder.Factory) } override fun initializeFromContentValues(values: ContentValues) { super.initializeFromContentValues(values) flags = values.getAsInteger(COLUMN_FLAGS) ?: 0 } override fun prepareForUpload(): String { var uid: String? = null Loading
app/src/main/java/at/bitfire/davdroid/resource/LocalGroup.kt +45 −52 Original line number Diff line number Diff line Loading @@ -43,32 +43,25 @@ class LocalGroup: AndroidGroup, LocalAddress { fun applyPendingMemberships(addressBook: LocalAddressBook) { Logger.log.info("Assigning memberships of contact groups") addressBook.provider!!.query( addressBook.groupsSyncUri(), arrayOf(Groups._ID, Groups.TITLE, COLUMN_PENDING_MEMBERS), "$COLUMN_PENDING_MEMBERS IS NOT NULL", null, null )?.use { cursor -> val batch = BatchOperation(addressBook.provider) while (cursor.moveToNext()) { val groupId = cursor.getLong(0) val groupName = cursor.getString(1) val pendingMemberUids = PendingMemberships.fromString(cursor.getString(2)).uids.toMutableSet() val currentMembers = addressBook.getByGroupMembership(groupId) addressBook.allGroups { group -> val groupId = group.id!! val pendingMemberUids = group.pendingMemberships.toMutableSet() val batch = BatchOperation(addressBook.provider!!) // required for workaround for Android 7 which sets DIRTY flag when only meta-data is changed val changeContactIDs = HashSet<Long>() // process members which are currently in this group, but shouldn't be for (currentMember in currentMembers) { val uid = currentMember.getContact().uid ?: continue for (currentMemberId in addressBook.getContactIdsByGroupMembership(groupId)) { val uid = addressBook.getContactUidFromId(currentMemberId) ?: continue if (!pendingMemberUids.contains(uid)) { Logger.log.fine("$currentMember removed from group $groupName (#$groupId); removing group membership") Logger.log.fine("$currentMemberId removed from group $groupId; removing group membership") val currentMember = addressBook.findContactById(currentMemberId) currentMember.removeGroupMemberships(batch) // Android 7 hack changeContactIDs += currentMember.id!! changeContactIDs += currentMemberId } // UID is processed, remove from pendingMembers Loading @@ -80,11 +73,11 @@ class LocalGroup: AndroidGroup, LocalAddress { for (missingMemberUid in pendingMemberUids) { val missingMember = addressBook.findContactByUid(missingMemberUid) if (missingMember == null) { Logger.log.warning("Group $groupName (#$groupId) has member $missingMemberUid which is not found in the address book; ignoring") Logger.log.warning("Group $groupId has member $missingMemberUid which is not found in the address book; ignoring") continue } Logger.log.fine("Assigning member $missingMember to group $groupName (#$groupId)") Logger.log.fine("Assigning member $missingMember to group $groupId") missingMember.addToGroup(batch, groupId) // Android 7 hack Loading @@ -100,7 +93,6 @@ class LocalGroup: AndroidGroup, LocalAddress { batch.commit() } } } } Loading @@ -111,13 +103,14 @@ class LocalGroup: AndroidGroup, LocalAddress { override var flags: Int = 0 var pendingMemberships = setOf<String>() constructor(addressBook: AndroidAddressBook<out AndroidContact, LocalGroup>, values: ContentValues) : super(addressBook, values) override fun initializeFromContentValues(values: ContentValues) { super.initializeFromContentValues(values) constructor(addressBook: AndroidAddressBook<out AndroidContact, LocalGroup>, values: ContentValues) : super(addressBook, values) { flags = values.getAsInteger(COLUMN_FLAGS) ?: 0 values.getAsString(COLUMN_PENDING_MEMBERS)?.let { members -> pendingMemberships = PendingMemberships.fromString(members).uids } } constructor(addressBook: AndroidAddressBook<out AndroidContact, LocalGroup>, contact: Contact, fileName: String?, eTag: String?, flags: Int) Loading
vcard4android @ af41314f Compare 60303f32 to af41314f Original line number Diff line number Diff line Subproject commit 60303f320b756e2865a6b3dea65ebd7a188ca823 Subproject commit af41314f13114f0b2cf9f93e18138cffb24a4d91