Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/bitfireAT/vcard4android.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRicki Hirner <hirner@bitfire.at>2021-08-02 14:34:05 +0300
committerRicki Hirner <hirner@bitfire.at>2021-08-02 14:34:18 +0300
commit3bc02c9dde4a22d6697e0adef1e82fcf714e0202 (patch)
tree02c06d834f31add0c877b32c263cce7c1fe3fc7d
parent327d5b4e7c5ba2e92889980d145dab7b4932be14 (diff)
Support DAVx5 strategies for groups
-rw-r--r--src/androidTest/java/at/bitfire/vcard4android/AndroidContactTest.kt10
-rw-r--r--src/androidTest/java/at/bitfire/vcard4android/AndroidGroupTest.kt6
-rw-r--r--src/main/java/at/bitfire/vcard4android/AndroidAddressBook.kt10
-rw-r--r--src/main/java/at/bitfire/vcard4android/AndroidContact.kt5
-rw-r--r--src/main/java/at/bitfire/vcard4android/AndroidGroup.kt114
-rw-r--r--src/main/java/at/bitfire/vcard4android/Contact.kt4
-rw-r--r--src/main/java/at/bitfire/vcard4android/ContactWriter.kt8
-rw-r--r--src/main/java/at/bitfire/vcard4android/datarow/ContactProcessor.kt1
-rw-r--r--src/test/java/at/bitfire/vcard4android/ContactTest.kt4
-rw-r--r--src/test/java/at/bitfire/vcard4android/ContactWriterTest.kt24
10 files changed, 101 insertions, 85 deletions
diff --git a/src/androidTest/java/at/bitfire/vcard4android/AndroidContactTest.kt b/src/androidTest/java/at/bitfire/vcard4android/AndroidContactTest.kt
index cb5a948..b366b83 100644
--- a/src/androidTest/java/at/bitfire/vcard4android/AndroidContactTest.kt
+++ b/src/androidTest/java/at/bitfire/vcard4android/AndroidContactTest.kt
@@ -81,7 +81,7 @@ class AndroidContactTest {
val contact = AndroidContact(addressBook, vcard, null, null)
contact.add()
- val contact2 = addressBook.findContactByID(contact.id!!)
+ val contact2 = addressBook.findContactById(contact.id!!)
try {
val vcard2 = contact2.getContact()
assertEquals(vcard.displayName, vcard2.displayName)
@@ -114,7 +114,7 @@ class AndroidContactTest {
val dbContact = AndroidContact(addressBook, contacts.first(), null, null)
dbContact.add()
- val dbContact2 = addressBook.findContactByID(dbContact.id!!)
+ val dbContact2 = addressBook.findContactById(dbContact.id!!)
try {
val contact2 = dbContact2.getContact()
assertEquals("Test", contact2.displayName)
@@ -136,7 +136,7 @@ class AndroidContactTest {
val contact = AndroidContact(addressBook, vcard, null, null)
contact.add()
- val contact2 = addressBook.findContactByID(contact.id!!)
+ val contact2 = addressBook.findContactById(contact.id!!)
try {
val vcard2 = contact2.getContact()
assertEquals(4000, vcard2.emails.size)
@@ -181,7 +181,7 @@ class AndroidContactTest {
* So, ADR value components may contain DQUOTE (0x22) and don't have to be encoded as defined in RFC 6868 */
val os = ByteArrayOutputStream()
- contact.writeVCard(VCardVersion.V4_0, GroupMethod.GROUP_VCARDS, os)
+ contact.writeVCard(VCardVersion.V4_0, os)
assertTrue(os.toString().contains("ADR;LABEL=My ^'Label^'\\nLine 2:;;Street \"Address\";;;;"))
}
@@ -194,7 +194,7 @@ class AndroidContactTest {
val contact = AndroidContact(addressBook, vcard, null, null)
contact.add()
- val contact2 = addressBook.findContactByID(contact.id!!)
+ val contact2 = addressBook.findContactById(contact.id!!)
try {
val vcard2 = contact2.getContact()
assertEquals(vcard.displayName, vcard2.displayName)
diff --git a/src/androidTest/java/at/bitfire/vcard4android/AndroidGroupTest.kt b/src/androidTest/java/at/bitfire/vcard4android/AndroidGroupTest.kt
index cff3c82..ca6cb1e 100644
--- a/src/androidTest/java/at/bitfire/vcard4android/AndroidGroupTest.kt
+++ b/src/androidTest/java/at/bitfire/vcard4android/AndroidGroupTest.kt
@@ -63,9 +63,9 @@ class AndroidGroupTest {
group.add()
val groups = addressBook.queryGroups("${ContactsContract.Groups.TITLE}=?", arrayOf(contact.displayName!!))
assertEquals(1, groups.size)
- val contact2 = groups.first().contact
- assertEquals(contact.displayName, contact2?.displayName)
- assertEquals(contact.note, contact2?.note)
+ val contact2 = groups.first().getContact()
+ assertEquals(contact.displayName, contact2.displayName)
+ assertEquals(contact.note, contact2.note)
// delete group
group.delete()
diff --git a/src/main/java/at/bitfire/vcard4android/AndroidAddressBook.kt b/src/main/java/at/bitfire/vcard4android/AndroidAddressBook.kt
index fcc325c..af0c1d6 100644
--- a/src/main/java/at/bitfire/vcard4android/AndroidAddressBook.kt
+++ b/src/main/java/at/bitfire/vcard4android/AndroidAddressBook.kt
@@ -80,13 +80,15 @@ open class AndroidAddressBook<T1: AndroidContact, T2: AndroidGroup>(
return groups
}
- fun findContactByID(id: Long) =
- queryContacts("${RawContacts._ID}=?", arrayOf(id.toString())).firstOrNull()
- ?: throw FileNotFoundException()
+ fun findContactById(id: Long) =
+ queryContacts("${RawContacts._ID}=?", arrayOf(id.toString())).firstOrNull() ?: throw FileNotFoundException()
- fun findContactByUID(uid: String) =
+ fun findContactByUid(uid: String) =
queryContacts("${AndroidContact.COLUMN_UID}=?", arrayOf(uid)).firstOrNull()
+ fun findGroupById(id: Long) =
+ queryGroups("${Groups._ID}=?", arrayOf(id.toString())).firstOrNull() ?: throw FileNotFoundException()
+
// helpers
diff --git a/src/main/java/at/bitfire/vcard4android/AndroidContact.kt b/src/main/java/at/bitfire/vcard4android/AndroidContact.kt
index d1f18fd..45ca96b 100644
--- a/src/main/java/at/bitfire/vcard4android/AndroidContact.kt
+++ b/src/main/java/at/bitfire/vcard4android/AndroidContact.kt
@@ -55,7 +55,6 @@ open class AndroidContact(
setContact(_contact)
}
-
/**
* Creates a new instance, initialized with metadata from the content provider. Usually used when reading a contact from an address book.
*/
@@ -137,8 +136,8 @@ open class AndroidContact(
return resultUri
}
- fun update(contact: Contact): Uri {
- setContact(contact)
+ fun update(data: Contact): Uri {
+ setContact(data)
val batch = BatchOperation(addressBook.provider!!)
val uri = rawContactSyncURI()
diff --git a/src/main/java/at/bitfire/vcard4android/AndroidGroup.kt b/src/main/java/at/bitfire/vcard4android/AndroidGroup.kt
index 3670c29..8447184 100644
--- a/src/main/java/at/bitfire/vcard4android/AndroidGroup.kt
+++ b/src/main/java/at/bitfire/vcard4android/AndroidGroup.kt
@@ -37,77 +37,91 @@ open class AndroidGroup(
var eTag: String? = null
constructor(addressBook: AndroidAddressBook<out AndroidContact, out AndroidGroup>, values: ContentValues): this(addressBook) {
- this.id = values.getAsLong(Groups._ID)
- this.fileName = values.getAsString(COLUMN_FILENAME)
- this.eTag = values.getAsString(COLUMN_ETAG)
+ initializeFromContentValues(values)
}
constructor(addressBook: AndroidAddressBook<out AndroidContact, out AndroidGroup>, contact: Contact, fileName: String? = null, eTag: String? = null): this(addressBook) {
- this.contact = contact
+ _contact = contact
this.fileName = fileName
this.eTag = eTag
}
- var contact: Contact? = null
+ protected open fun initializeFromContentValues(values: ContentValues) {
+ id = values.getAsLong(Groups._ID)
+ fileName = values.getAsString(COLUMN_FILENAME)
+ eTag = values.getAsString(COLUMN_ETAG)
+ }
+
+
+ /**
+ * Cached copy of the [Contact]. If this is null, [getContact] must generate the [Contact]
+ * from the database and then set this property.
+ */
+ protected var _contact: Contact? = null
+
/**
- * Creates a [Contact] (representation of a vCard) from the group.
+ * Fetches group data from the content provider.
+ *
* @throws IllegalArgumentException if group has not been saved yet
* @throws FileNotFoundException when the group is not available (anymore)
* @throws RemoteException on contact provider errors
*/
- get() {
- field?.let { return field }
-
- val id = requireNotNull(id)
- val c = Contact()
- addressBook.provider!!.query(addressBook.syncAdapterURI(ContentUris.withAppendedId(Groups.CONTENT_URI, id)),
- arrayOf(COLUMN_UID, Groups.TITLE, Groups.NOTES), null, null, null)?.use { cursor ->
- if (!cursor.moveToNext())
- throw FileNotFoundException("Contact group not found")
-
- c.uid = cursor.getString(0)
- c.group = true
- c.displayName = cursor.getString(1)
- c.note = cursor.getString(2)
- }
+ fun getContact(): Contact {
+ _contact?.let { return it }
- // query UIDs of all contacts which are member of the group
- addressBook.provider.query(addressBook.syncAdapterURI(ContactsContract.Data.CONTENT_URI),
- arrayOf(Data.RAW_CONTACT_ID),
- GroupMembership.MIMETYPE + "=? AND " + GroupMembership.GROUP_ROW_ID + "=?",
- arrayOf(GroupMembership.CONTENT_ITEM_TYPE, id.toString()), null)?.use { cursor ->
- while (cursor.moveToNext()) {
- val contactID = cursor.getLong(0)
- Constants.log.fine("Member ID: $contactID")
-
- addressBook.provider.query(addressBook.syncAdapterURI(ContentUris.withAppendedId(RawContacts.CONTENT_URI, contactID)),
- arrayOf(AndroidContact.COLUMN_UID), null, null, null)?.use { cursor ->
- if (cursor.moveToNext()) {
- val uid = cursor.getString(0)
- if (!uid.isNullOrEmpty()) {
- Constants.log.fine("Found member of group: $uid")
- c.members += uid
- }
- }
+ val id = requireNotNull(id)
+ val contact = Contact()
+ addressBook.provider!!.query(addressBook.syncAdapterURI(ContentUris.withAppendedId(Groups.CONTENT_URI, id)),
+ arrayOf(COLUMN_UID, Groups.TITLE, Groups.NOTES), null, null, null)?.use { cursor ->
+ if (!cursor.moveToNext())
+ throw FileNotFoundException("Contact group not found")
+
+ contact.group = true
+ contact.uid = cursor.getString(0)
+ contact.displayName = cursor.getString(1)
+ contact.note = cursor.getString(2)
+ }
+
+ // get all contacts which are member of the group
+ addressBook.provider.query(addressBook.syncAdapterURI(ContactsContract.Data.CONTENT_URI),
+ arrayOf(Data.RAW_CONTACT_ID),
+ GroupMembership.MIMETYPE + "=? AND " + GroupMembership.GROUP_ROW_ID + "=?",
+ arrayOf(GroupMembership.CONTENT_ITEM_TYPE, id.toString()), null)?.use { membershipCursor ->
+ while (membershipCursor.moveToNext()) {
+ val contactId = membershipCursor.getLong(0)
+ Constants.log.fine("Member ID: $contactId")
+
+ // get UID from the member
+ addressBook.provider.query(addressBook.syncAdapterURI(ContentUris.withAppendedId(RawContacts.CONTENT_URI, contactId)),
+ arrayOf(AndroidContact.COLUMN_UID), null, null, null)?.use { rawContactCursor ->
+ if (rawContactCursor.moveToNext()) {
+ val uid = rawContactCursor.getString(0)
+ if (!uid.isNullOrBlank()) {
+ Constants.log.fine("Found member of group: $uid")
+ // add UID to contact members (vCard MEMBERS field)
+ contact.members += uid
+ } else
+ Constants.log.severe("Couldn't add member $contactId to group contact because it doesn't have an UID (yet)")
}
}
}
-
- field = c
- return c
}
+ _contact = contact
+ return contact
+ }
+
@CallSuper
protected open fun contentValues(): ContentValues {
val values = ContentValues()
values.put(COLUMN_FILENAME, fileName)
values.put(COLUMN_ETAG, eTag)
- contact?.let {
- values.put(COLUMN_UID, it.uid)
- values.put(Groups.TITLE, it.displayName)
- values.put(Groups.NOTES, it.note)
- }
+
+ val contact = getContact()
+ values.put(COLUMN_UID, contact.uid)
+ values.put(Groups.TITLE, contact.displayName)
+ values.put(Groups.NOTES, contact.note)
return values
}
@@ -132,12 +146,12 @@ open class AndroidGroup(
/**
* Updates a group from a [Contact], which represents a vCard received from the
* CardDAV server.
- * @param contact data object to take group title, members etc. from
+ * @param data data object to take group title, members etc. from
* @return number of affected rows
* @throws RemoteException on contact provider errors
*/
- fun update(contact: Contact): Uri {
- this.contact = contact
+ fun update(data: Contact): Uri {
+ _contact = data
return update(contentValues())
}
diff --git a/src/main/java/at/bitfire/vcard4android/Contact.kt b/src/main/java/at/bitfire/vcard4android/Contact.kt
index 2d5ad6d..6935570 100644
--- a/src/main/java/at/bitfire/vcard4android/Contact.kt
+++ b/src/main/java/at/bitfire/vcard4android/Contact.kt
@@ -127,8 +127,8 @@ class Contact {
@Throws(IOException::class)
- fun writeVCard(vCardVersion: VCardVersion, groupMethod: GroupMethod, os: OutputStream) {
- val generator = ContactWriter.fromContact(this, vCardVersion, groupMethod)
+ fun writeVCard(vCardVersion: VCardVersion, os: OutputStream) {
+ val generator = ContactWriter.fromContact(this, vCardVersion)
generator.writeVCard(os)
}
diff --git a/src/main/java/at/bitfire/vcard4android/ContactWriter.kt b/src/main/java/at/bitfire/vcard4android/ContactWriter.kt
index a26bf94..a737960 100644
--- a/src/main/java/at/bitfire/vcard4android/ContactWriter.kt
+++ b/src/main/java/at/bitfire/vcard4android/ContactWriter.kt
@@ -21,7 +21,7 @@ import java.util.logging.Level
*
* Properties which are not supported by the target vCard version have to be converted appropriately.
*/
-class ContactWriter private constructor(val contact: Contact, val version: VCardVersion, val groupMethod: GroupMethod) {
+class ContactWriter private constructor(val contact: Contact, val version: VCardVersion) {
private val unknownProperties = LinkedList<VCardProperty>()
val vCard = VCard()
@@ -31,8 +31,8 @@ class ContactWriter private constructor(val contact: Contact, val version: VCard
companion object {
- fun fromContact(contact: Contact, version: VCardVersion, groupMethod: GroupMethod) =
- ContactWriter(contact, version, groupMethod)
+ fun fromContact(contact: Contact, version: VCardVersion) =
+ ContactWriter(contact, version)
}
@@ -140,7 +140,7 @@ class ContactWriter private constructor(val contact: Contact, val version: VCard
}
private fun addKindAndMembers() {
- if (contact.group && groupMethod == GroupMethod.GROUP_VCARDS) {
+ if (contact.group) {
// TODO Use urn:uuid only when applicable
if (version == VCardVersion.V4_0) { // vCard4
vCard.kind = Kind.group()
diff --git a/src/main/java/at/bitfire/vcard4android/datarow/ContactProcessor.kt b/src/main/java/at/bitfire/vcard4android/datarow/ContactProcessor.kt
index 178549a..c34470a 100644
--- a/src/main/java/at/bitfire/vcard4android/datarow/ContactProcessor.kt
+++ b/src/main/java/at/bitfire/vcard4android/datarow/ContactProcessor.kt
@@ -3,6 +3,7 @@ package at.bitfire.vcard4android.datarow
import android.content.ContentProviderClient
import android.content.ContentValues
import android.net.Uri
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership
import android.provider.ContactsContract.RawContacts
import at.bitfire.vcard4android.AndroidContact
import at.bitfire.vcard4android.BatchOperation
diff --git a/src/test/java/at/bitfire/vcard4android/ContactTest.kt b/src/test/java/at/bitfire/vcard4android/ContactTest.kt
index d003f26..786ad30 100644
--- a/src/test/java/at/bitfire/vcard4android/ContactTest.kt
+++ b/src/test/java/at/bitfire/vcard4android/ContactTest.kt
@@ -33,13 +33,13 @@ class ContactTest {
private fun regenerate(c: Contact, vCardVersion: VCardVersion): Contact {
val os = ByteArrayOutputStream()
- c.writeVCard(vCardVersion, GroupMethod.CATEGORIES, os)
+ c.writeVCard(vCardVersion, os)
return Contact.fromReader(InputStreamReader(ByteArrayInputStream(os.toByteArray()), Charsets.UTF_8), null).first()
}
private fun toString(c: Contact, groupMethod: GroupMethod, vCardVersion: VCardVersion): String {
val os = ByteArrayOutputStream()
- c.writeVCard(vCardVersion, groupMethod, os)
+ c.writeVCard(vCardVersion, os)
return os.toString()
}
diff --git a/src/test/java/at/bitfire/vcard4android/ContactWriterTest.kt b/src/test/java/at/bitfire/vcard4android/ContactWriterTest.kt
index 8eae372..d8a5dde 100644
--- a/src/test/java/at/bitfire/vcard4android/ContactWriterTest.kt
+++ b/src/test/java/at/bitfire/vcard4android/ContactWriterTest.kt
@@ -192,7 +192,7 @@ class ContactWriterTest {
@Test
fun testKindAndMember_vCard3() {
- val vCard = generate(GroupMethod.GROUP_VCARDS, VCardVersion.V3_0) {
+ val vCard = generate(VCardVersion.V3_0) {
group = true
members += "member1"
}
@@ -202,7 +202,7 @@ class ContactWriterTest {
@Test
fun testKindAndMember_vCard4() {
- val vCard = generate(GroupMethod.GROUP_VCARDS, VCardVersion.V4_0) {
+ val vCard = generate(VCardVersion.V4_0) {
group = true
members += "member1"
}
@@ -478,7 +478,7 @@ class ContactWriterTest {
@Test
fun testRewritePartialDate_vCard3_Date() {
- val generator = ContactWriter.fromContact(Contact(), VCardVersion.V3_0, GroupMethod.GROUP_VCARDS)
+ val generator = ContactWriter.fromContact(Contact(), VCardVersion.V3_0)
val date = Birthday(Date(121, 6, 30))
generator.rewritePartialDate(date)
assertEquals(Date(121, 6, 30), date.date)
@@ -487,7 +487,7 @@ class ContactWriterTest {
@Test
fun testRewritePartialDate_vCard4_Date() {
- val generator = ContactWriter.fromContact(Contact(), VCardVersion.V4_0, GroupMethod.GROUP_VCARDS)
+ val generator = ContactWriter.fromContact(Contact(), VCardVersion.V4_0)
val date = Birthday(Date(121, 6, 30))
generator.rewritePartialDate(date)
assertEquals(Date(121, 6, 30), date.date)
@@ -497,7 +497,7 @@ class ContactWriterTest {
@Test
fun testRewritePartialDate_vCard3_PartialDateWithYear() {
- val generator = ContactWriter.fromContact(Contact(), VCardVersion.V3_0, GroupMethod.GROUP_VCARDS)
+ val generator = ContactWriter.fromContact(Contact(), VCardVersion.V3_0)
val date = Birthday(PartialDate.parse("20210730"))
generator.rewritePartialDate(date)
assertEquals(Date(121, 6, 30), date.date)
@@ -507,7 +507,7 @@ class ContactWriterTest {
@Test
fun testRewritePartialDate_vCard4_PartialDateWithYear() {
- val generator = ContactWriter.fromContact(Contact(), VCardVersion.V4_0, GroupMethod.GROUP_VCARDS)
+ val generator = ContactWriter.fromContact(Contact(), VCardVersion.V4_0)
val date = Birthday(PartialDate.parse("20210730"))
generator.rewritePartialDate(date)
assertNull(date.date)
@@ -517,7 +517,7 @@ class ContactWriterTest {
@Test
fun testRewritePartialDate_vCard3_PartialDateWithoutYear() {
- val generator = ContactWriter.fromContact(Contact(), VCardVersion.V3_0, GroupMethod.GROUP_VCARDS)
+ val generator = ContactWriter.fromContact(Contact(), VCardVersion.V3_0)
val date = Birthday(PartialDate.parse("--0730"))
generator.rewritePartialDate(date)
assertEquals(Date(-300+4, 6, 30), date.date)
@@ -528,7 +528,7 @@ class ContactWriterTest {
@Test
fun testRewritePartialDate_vCard4_PartialDateWithoutYear() {
- val generator = ContactWriter.fromContact(Contact(), VCardVersion.V4_0, GroupMethod.GROUP_VCARDS)
+ val generator = ContactWriter.fromContact(Contact(), VCardVersion.V4_0)
val date = Birthday(PartialDate.parse("--0730"))
generator.rewritePartialDate(date)
assertNull(date.date)
@@ -539,7 +539,7 @@ class ContactWriterTest {
@Test
fun testWriteVCard() {
- val generator = ContactWriter.fromContact(Contact(), VCardVersion.V4_0, GroupMethod.GROUP_VCARDS)
+ val generator = ContactWriter.fromContact(Contact(), VCardVersion.V4_0)
generator.vCard.revision = Revision(Calendar.getInstance(TimeZone.getTimeZone(ZoneOffset.UTC.id)).apply {
set(2021, 6, 30, 1, 2, 3)
})
@@ -564,7 +564,7 @@ class ContactWriterTest {
})
}
ContactWriter
- .fromContact(contact, VCardVersion.V4_0, GroupMethod.GROUP_VCARDS)
+ .fromContact(contact, VCardVersion.V4_0)
.writeVCard(stream)
assertTrue(stream.toString().contains("ADR;LABEL=\"Li^^ne 1,1 - ^' -\":;;Line1;;;;Line2"))
}
@@ -572,10 +572,10 @@ class ContactWriterTest {
// helpers
- private fun generate(groupMethod: GroupMethod = GroupMethod.GROUP_VCARDS, version: VCardVersion = VCardVersion.V4_0, prepare: Contact.() -> Unit): VCard {
+ private fun generate(version: VCardVersion = VCardVersion.V4_0, prepare: Contact.() -> Unit): VCard {
val contact = Contact()
contact.run(prepare)
- return ContactWriter.fromContact(contact, version, groupMethod).vCard
+ return ContactWriter.fromContact(contact, version).vCard
}
} \ No newline at end of file