Skip to content

Commit

Permalink
Add support for Sip addresses
Browse files Browse the repository at this point in the history
  • Loading branch information
alexstyl committed Dec 31, 2021
1 parent 0306104 commit a2f9813
Show file tree
Hide file tree
Showing 14 changed files with 180 additions and 3 deletions.
Expand Up @@ -9,6 +9,7 @@ import com.alexstyl.contactstore.ContactColumn.Organization
import com.alexstyl.contactstore.ContactColumn.Phones
import com.alexstyl.contactstore.ContactColumn.PostalAddresses
import com.alexstyl.contactstore.ContactColumn.Relations
import com.alexstyl.contactstore.ContactColumn.SipAddresses
import com.alexstyl.contactstore.ContactColumn.WebAddresses
import com.alexstyl.contactstore.Label.RelationManager
import kotlinx.coroutines.ExperimentalCoroutinesApi
Expand Down Expand Up @@ -235,4 +236,27 @@ class AddValuesToExistingContactContactStoreTest : ContactStoreTestBase() {

assertContactUpdatedNoId(expected)
}

@Test
fun updatesSipAddresses(): Unit = runBlocking {
val contact = buildStoreContact(Names, SipAddresses) {
firstName = "Paolo"
lastName = "Melendez"
}

val expected = contact.mutableCopy().apply {
sipAddresses.add(
LabeledValue(
SipAddress("123"),
Label.LocationHome
)
)
}
store.execute {
update(expected)
}

assertContactUpdatedNoId(expected)
}

}
Expand Up @@ -9,6 +9,7 @@ import com.alexstyl.contactstore.ContactColumn.Organization
import com.alexstyl.contactstore.ContactColumn.Phones
import com.alexstyl.contactstore.ContactColumn.PostalAddresses
import com.alexstyl.contactstore.ContactColumn.Relations
import com.alexstyl.contactstore.ContactColumn.SipAddresses
import com.alexstyl.contactstore.ContactColumn.WebAddresses
import com.alexstyl.contactstore.Label.DateBirthday
import com.alexstyl.contactstore.Label.LocationHome
Expand Down Expand Up @@ -307,4 +308,23 @@ class ContactStoreInsertContactTest : ContactStoreTestBase() {

assertOnlyContact(actual = actual, expected = expected)
}

@Test
fun insertsContactWithSip(): Unit = runBlocking {
store.execute {
insert {
sipAddress(address = "123", label = LocationHome)
}
}

val actual = store.fetchContacts(columnsToFetch = listOf(SipAddresses)).first()
val expected = contact(
sipAddresses = listOf(
LabeledValue(SipAddress(raw = "123"), LocationHome)
),
columns = listOf(SipAddresses)
)

assertOnlyContact(actual = actual, expected = expected)
}
}
Expand Up @@ -70,6 +70,7 @@ abstract class ContactStoreTestBase {
events: List<LabeledValue<EventDate>> = emptyList(),
webAddresses: List<LabeledValue<WebAddress>> = emptyList(),
imAddresses: List<LabeledValue<ImAddress>> = emptyList(),
sipAddresses: List<LabeledValue<SipAddress>> = emptyList(),
relations : List<LabeledValue<Relation>> = emptyList(),
note: Note? = null,
prefix: String? = null,
Expand All @@ -89,6 +90,7 @@ abstract class ContactStoreTestBase {
lastName = lastName,
events = events,
postalAddresses = postalAddresses,
sipAddresses = sipAddresses,
note = note,
columns = columns,
webAddresses = webAddresses,
Expand Down
Expand Up @@ -11,6 +11,7 @@ import com.alexstyl.contactstore.ContactColumn.Organization
import com.alexstyl.contactstore.ContactColumn.Phones
import com.alexstyl.contactstore.ContactColumn.PostalAddresses
import com.alexstyl.contactstore.ContactColumn.Relations
import com.alexstyl.contactstore.ContactColumn.SipAddresses
import com.alexstyl.contactstore.ContactColumn.WebAddresses
import org.hamcrest.Description
import org.hamcrest.Matcher
Expand Down Expand Up @@ -71,6 +72,10 @@ class EqualContentsContactMatcher(
putCommaIfNeeded()
append("webAddresses = ${labeledValues(webAddresses)}")
}
if (containsColumn(SipAddresses)) {
putCommaIfNeeded()
append("sipAddresses = ${labeledValues(sipAddresses)}")
}
if (containsColumn(Events)) {
putCommaIfNeeded()
append("events = ${labeledValues(events)}")
Expand Down Expand Up @@ -126,6 +131,10 @@ class EqualContentsContactMatcher(
mismatchDescription.appendText("imAddresses were ${labeledValues(actual.imAddresses)}")
false
}
sipAreDifferent(actual) -> {
mismatchDescription.appendText("sipAddresses were ${labeledValues(actual.sipAddresses)}")
false
}
organizationIsDifferent(actual) -> {
mismatchDescription.appendText("organization was ${actual.organization}, jobTitle was ${actual.jobTitle}")
false
Expand Down Expand Up @@ -177,6 +186,13 @@ class EqualContentsContactMatcher(
return areLabeledValuesDifferentIgnoringId(actual.imAddresses, expected.imAddresses)
}

private fun sipAreDifferent(actual: Contact): Boolean {
if (expected.containsColumn(SipAddresses).not()) {
return false
}
return areLabeledValuesDifferentIgnoringId(actual.sipAddresses, expected.sipAddresses)
}

private fun namesAreDifferent(actual: Contact): Boolean {
if (expected.containsColumn(Names).not()) {
return false
Expand Down
10 changes: 10 additions & 0 deletions library/src/main/java/com/alexstyl/contactstore/Contact.kt
Expand Up @@ -22,6 +22,7 @@ import com.alexstyl.contactstore.ContactColumn.Organization
import com.alexstyl.contactstore.ContactColumn.Phones
import com.alexstyl.contactstore.ContactColumn.PostalAddresses
import com.alexstyl.contactstore.ContactColumn.Relations
import com.alexstyl.contactstore.ContactColumn.SipAddresses
import com.alexstyl.contactstore.ContactColumn.WebAddresses

interface Contact {
Expand Down Expand Up @@ -107,6 +108,11 @@ interface Contact {
*/
val phones: List<LabeledValue<PhoneNumber>>

/**
* Requires: [ContactColumn.SipAddresses]
*/
val sipAddresses: List<LabeledValue<SipAddress>>

/**
* Requires: [ContactColumn.Mails]
*/
Expand Down Expand Up @@ -194,6 +200,10 @@ fun Contact.mutableCopy(): MutableContact {
webAddresses.toMutableList()
else
mutableListOf(),
sipAddresses = if (containsColumn(SipAddresses))
sipAddresses.toMutableList()
else
mutableListOf(),
imAddresses = if (containsColumn(ImAddresses)) imAddresses.toMutableList() else mutableListOf(),
relations = if(containsColumn(Relations)) relations.toMutableList() else mutableListOf(),
note = if (containsColumn(Note)) note else null,
Expand Down
Expand Up @@ -72,6 +72,11 @@ sealed class ContactColumn {
*/
object ImAddresses : ContactColumn()

/**
* A column that will populate the [Contact.sipAddresses] field of all queried contacts when requested.
*/
object SipAddresses : ContactColumn()

/**
* A column that will populate the [Contact.relations] field of all queried contacts when requested.
*/
Expand All @@ -93,5 +98,6 @@ fun standardColumns(): List<ContactColumn> {
ContactColumn.GroupMemberships,
ContactColumn.ImAddresses,
ContactColumn.Relations,
ContactColumn.SipAddresses,
)
}
22 changes: 22 additions & 0 deletions library/src/main/java/com/alexstyl/contactstore/ContactQueries.kt
Expand Up @@ -10,6 +10,7 @@ import android.provider.ContactsContract.CommonDataKinds.Organization as Organiz
import android.provider.ContactsContract.CommonDataKinds.Phone as PhoneColumns
import android.provider.ContactsContract.CommonDataKinds.Photo as PhotoColumns
import android.provider.ContactsContract.CommonDataKinds.Relation as RelationColumns
import android.provider.ContactsContract.CommonDataKinds.SipAddress as SipColumns
import android.provider.ContactsContract.CommonDataKinds.StructuredName as NameColumns
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal as PostalColumns
import android.provider.ContactsContract.CommonDataKinds.Website as WebColumns
Expand Down Expand Up @@ -228,6 +229,7 @@ internal class ContactQueries(
val phones = mutableSetOf<LabeledValue<PhoneNumber>>()
val mails = mutableSetOf<LabeledValue<MailAddress>>()
val webAddresses = mutableSetOf<LabeledValue<WebAddress>>()
val sipAddresses = mutableSetOf<LabeledValue<SipAddress>>()
val events = mutableSetOf<LabeledValue<EventDate>>()
val imAddresses = mutableSetOf<LabeledValue<ImAddress>>()
val relations = mutableSetOf<LabeledValue<Relation>>()
Expand Down Expand Up @@ -325,6 +327,14 @@ internal class ContactQueries(
events.add(entry)
}
}
SipColumns.CONTENT_ITEM_TYPE -> {
val address = row[SipColumns.SIP_ADDRESS]
val id = row[SipColumns._ID].toLongOrNull()
if (address.isNotBlank() && id != null) {
val value = LabeledValue(SipAddress(address), sipLabel(row), id)
sipAddresses.add(value)
}
}
PostalColumns.CONTENT_ITEM_TYPE -> {
val formattedAddress = row[PostalColumns.FORMATTED_ADDRESS]
val id = row[PostalColumns._ID].toLongOrNull()
Expand Down Expand Up @@ -422,6 +432,7 @@ internal class ContactQueries(
nickname = nickname,
phoneticMiddleName = phoneticMiddleName,
phoneticNameStyle = phoneticNameStyle,
sipAddresses = sipAddresses.toList(),
groups = groupIds.toList(),
linkedAccountValues = linkedAccountValues.toList(),
imAddresses = imAddresses.toList(),
Expand All @@ -430,6 +441,16 @@ internal class ContactQueries(
}
}

private fun sipLabel(row: Cursor): Label {
return when (row[SipColumns.TYPE].toIntOrNull()) {
SipColumns.TYPE_HOME -> Label.LocationHome
SipColumns.TYPE_OTHER -> Label.Other
SipColumns.TYPE_WORK -> Label.LocationWork
SipColumns.TYPE_CUSTOM -> Label.Custom(row[SipColumns.LABEL])
else -> Label.Other
}
}

private fun relationLabel(row: Cursor): Label {
return when (row[RelationColumns.TYPE].toIntOrNull()) {
RelationColumns.TYPE_ASSISTANT -> Label.PhoneNumberAssistant
Expand Down Expand Up @@ -491,6 +512,7 @@ internal class ContactQueries(
GroupMemberships -> GroupColumns.CONTENT_ITEM_TYPE
ImAddresses -> ImColumns.CONTENT_ITEM_TYPE
Relations -> RelationColumns.CONTENT_ITEM_TYPE
SipAddresses -> SipColumns.CONTENT_ITEM_TYPE
is LinkedAccountValues ->
error("Tried to map a LinkedAccountColumn as standard column")
}
Expand Down
Expand Up @@ -33,6 +33,7 @@ fun SaveRequest.insert(builder: MutableContactBuilder.() -> Unit) {
postalAddresses.addAll(values.postalAddresses)
webAddresses.addAll(values.webAddresses)
groups.addAll(values.groupMemberships)
sipAddresses.addAll(values.sipAddresses)
relations.addAll(values.relations)
imAddresses.addAll(values.imAddresses)
})
Expand Down
Expand Up @@ -61,6 +61,8 @@ data class ImAddress(
val protocol: String,
)

data class SipAddress(val raw: String)

internal fun GroupMembership.requireId(): Long {
return requireNotNull(_id)
}
Expand Down
Expand Up @@ -12,6 +12,7 @@ import android.provider.ContactsContract.CommonDataKinds.StructuredName as NameC
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal as PostalColumns
import android.provider.ContactsContract.CommonDataKinds.Website as WebAddressColumns
import android.provider.ContactsContract.CommonDataKinds.Relation as RelationColumns
import android.provider.ContactsContract.CommonDataKinds.SipAddress as SipColumns
import android.content.ContentProviderOperation
import android.content.ContentProviderOperation.newDelete
import android.content.ContentProviderOperation.newInsert
Expand All @@ -33,6 +34,7 @@ import com.alexstyl.contactstore.ContactColumn.Organization
import com.alexstyl.contactstore.ContactColumn.Phones
import com.alexstyl.contactstore.ContactColumn.PostalAddresses
import com.alexstyl.contactstore.ContactColumn.Relations
import com.alexstyl.contactstore.ContactColumn.SipAddresses
import com.alexstyl.contactstore.ContactColumn.WebAddresses
import com.alexstyl.contactstore.utils.get
import com.alexstyl.contactstore.utils.runQuery
Expand Down Expand Up @@ -64,8 +66,9 @@ internal class ExistingContactOperationsFactory(
updateGroupMembership(newContact = contact, oldContact = existingContact) +
updatePostalAddresses(newContact = contact, oldContact = existingContact) +
updateImAddresses(newContact = contact, oldContact = existingContact) +
updateSipAddresses(newContact = contact, oldContact = existingContact) +
updateRelations(newContact = contact, oldContact = existingContact) +
replaceWebAddresses(newContact = contact, oldContact = existingContact)
updateWebAddresses(newContact = contact, oldContact = existingContact)
}

private fun updateGroupMembership(
Expand Down Expand Up @@ -309,6 +312,24 @@ internal class ExistingContactOperationsFactory(
.withImLabel(labeledValue.label)
}
}

private fun updateSipAddresses(
newContact: MutableContact,
oldContact: Contact
): List<ContentProviderOperation> {
if (newContact.containsColumn(SipAddresses).not()) {
return emptyList()
}
return buildOperations(
forContactId = newContact.contactId,
oldValues = oldContact.sipAddresses,
newValues = newContact.sipAddresses,
mimeType = SipColumns.CONTENT_ITEM_TYPE,
) { labeledValue ->
withValue(SipColumns.SIP_ADDRESS, labeledValue.value.raw)
.withSipLabel(labeledValue.label)
}
}

private fun updateRelations(
newContact: MutableContact,
Expand Down Expand Up @@ -367,7 +388,7 @@ internal class ExistingContactOperationsFactory(
}
}

private fun replaceWebAddresses(
private fun updateWebAddresses(
newContact: MutableContact,
oldContact: Contact
): List<ContentProviderOperation> {
Expand Down
Expand Up @@ -12,6 +12,7 @@ import com.alexstyl.contactstore.ContactColumn.Organization
import com.alexstyl.contactstore.ContactColumn.Phones
import com.alexstyl.contactstore.ContactColumn.PostalAddresses
import com.alexstyl.contactstore.ContactColumn.Relations
import com.alexstyl.contactstore.ContactColumn.SipAddresses
import com.alexstyl.contactstore.ContactColumn.WebAddresses

class MutableContact internal constructor(
Expand Down Expand Up @@ -41,6 +42,7 @@ class MutableContact internal constructor(
groups: MutableList<GroupMembership>,
linkedAccountValues: List<LinkedAccountValue>,
imAddresses: MutableList<LabeledValue<ImAddress>>,
sipAddresses: MutableList<LabeledValue<SipAddress>>,
relations: MutableList<LabeledValue<Relation>>,
override val columns: List<ContactColumn>,
) : Contact {
Expand All @@ -55,6 +57,8 @@ class MutableContact internal constructor(
by requireColumn(WebAddresses, webAddresses)
override val imAddresses: MutableList<LabeledValue<ImAddress>>
by requireColumn(ImAddresses, imAddresses)
override val sipAddresses: MutableList<LabeledValue<SipAddress>>
by requireColumn(SipAddresses, sipAddresses)

override val linkedAccountValues: List<LinkedAccountValue>
by requireAnyLinkedAccountColumn(linkedAccountValues)
Expand Down Expand Up @@ -87,6 +91,7 @@ class MutableContact internal constructor(
events = mutableListOf(),
postalAddresses = mutableListOf(),
webAddresses = mutableListOf(),
sipAddresses = mutableListOf(),
relations = mutableListOf(),
note = null,
isStarred = false,
Expand Down
Expand Up @@ -47,6 +47,10 @@ data class MutableContactBuilder(
val groupMemberships: List<GroupMembership>
get() = _groups.toList()

private val _sipAddresses: MutableList<LabeledValue<SipAddress>> = mutableListOf()
val sipAddresses: List<LabeledValue<SipAddress>>
get() = _sipAddresses.toList()

private val _relations: MutableList<LabeledValue<Relation>> = mutableListOf()
val relations: List<LabeledValue<Relation>>
get() = _relations.toList()
Expand Down Expand Up @@ -125,4 +129,8 @@ data class MutableContactBuilder(
fun relation(name: String, label: Label) {
_relations.add(LabeledValue(Relation(name = name), label))
}

fun sipAddress(address: String, label: Label) {
_sipAddresses.add(LabeledValue(SipAddress(address), label))
}
}

0 comments on commit a2f9813

Please sign in to comment.