mirror of
https://github.com/etesync/android
synced 2025-01-11 08:10:58 +00:00
Support relations the VCard 4.0 way (closes #278)
This commit is contained in:
parent
b5c99265c3
commit
f1eabb6227
@ -18,8 +18,11 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import at.bitfire.davdroid.Constants;
|
||||
@ -27,8 +30,10 @@ import ezvcard.Ezvcard;
|
||||
import ezvcard.VCard;
|
||||
import ezvcard.VCardVersion;
|
||||
import ezvcard.ValidationWarnings;
|
||||
import ezvcard.Warning;
|
||||
import ezvcard.parameter.EmailType;
|
||||
import ezvcard.parameter.ImageType;
|
||||
import ezvcard.parameter.RelatedType;
|
||||
import ezvcard.parameter.TelephoneType;
|
||||
import ezvcard.property.Address;
|
||||
import ezvcard.property.Anniversary;
|
||||
@ -44,6 +49,7 @@ import ezvcard.property.Organization;
|
||||
import ezvcard.property.Photo;
|
||||
import ezvcard.property.ProductId;
|
||||
import ezvcard.property.RawProperty;
|
||||
import ezvcard.property.Related;
|
||||
import ezvcard.property.Revision;
|
||||
import ezvcard.property.Role;
|
||||
import ezvcard.property.Sound;
|
||||
@ -53,6 +59,8 @@ import ezvcard.property.Telephone;
|
||||
import ezvcard.property.Title;
|
||||
import ezvcard.property.Uid;
|
||||
import ezvcard.property.Url;
|
||||
import ezvcard.property.VCardProperty;
|
||||
import ezvcard.util.ListMultimap;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
@ -83,6 +91,13 @@ public class Contact extends Resource {
|
||||
PHONE_TYPE_RADIO = TelephoneType.get("X-RADIO"),
|
||||
PHONE_TYPE_ASSISTANT = TelephoneType.get("X-ASSISTANT"),
|
||||
PHONE_TYPE_MMS = TelephoneType.get("X-MMS");
|
||||
public final static RelatedType
|
||||
RELATED_TYPE_BROTHER = RelatedType.get("brother"),
|
||||
RELATED_TYPE_FATHER = RelatedType.get("father"),
|
||||
RELATED_TYPE_MANAGER = RelatedType.get("manager"),
|
||||
RELATED_TYPE_MOTHER = RelatedType.get("mother"),
|
||||
RELATED_TYPE_REFERRED_BY = RelatedType.get("referred-by"),
|
||||
RELATED_TYPE_SISTER = RelatedType.get("sister");
|
||||
|
||||
@Getter @Setter private String unknownProperties;
|
||||
|
||||
@ -100,13 +115,13 @@ public class Contact extends Resource {
|
||||
@Getter @Setter private Anniversary anniversary;
|
||||
@Getter @Setter private Birthday birthDay;
|
||||
|
||||
@Getter private List<Telephone> phoneNumbers = new LinkedList<Telephone>();
|
||||
@Getter private List<Email> emails = new LinkedList<Email>();
|
||||
@Getter private List<Impp> impps = new LinkedList<Impp>();
|
||||
@Getter private List<Address> addresses = new LinkedList<Address>();
|
||||
@Getter private List<String> categories = new LinkedList<String>();
|
||||
@Getter private List<String> URLs = new LinkedList<String>();
|
||||
|
||||
@Getter private List<Telephone> phoneNumbers = new LinkedList<>();
|
||||
@Getter private List<Email> emails = new LinkedList<>();
|
||||
@Getter private List<Impp> impps = new LinkedList<>();
|
||||
@Getter private List<Address> addresses = new LinkedList<>();
|
||||
@Getter private List<String> categories = new LinkedList<>();
|
||||
@Getter private List<String> URLs = new LinkedList<>();
|
||||
@Getter private List<Related> relations = new LinkedList<>();
|
||||
|
||||
/* instance methods */
|
||||
|
||||
@ -278,7 +293,17 @@ public class Contact extends Resource {
|
||||
// ANNIVERSARY
|
||||
anniversary = vcard.getAnniversary();
|
||||
vcard.removeProperties(Anniversary.class);
|
||||
|
||||
|
||||
// RELATED
|
||||
for (Related related : vcard.getRelations()) {
|
||||
String text = related.getText();
|
||||
if (!StringUtils.isNotEmpty(text)) {
|
||||
// process only free-form relations with text
|
||||
relations.add(related);
|
||||
vcard.removeProperty(related);
|
||||
}
|
||||
}
|
||||
|
||||
// X-SIP
|
||||
for (RawProperty sip : vcard.getExtendedProperties(PROPERTY_SIP))
|
||||
impps.add(new Impp("sip", sip.getValue()));
|
||||
@ -411,6 +436,9 @@ public class Contact extends Resource {
|
||||
// PHOTO
|
||||
if (photo != null)
|
||||
vcard.addPhoto(new Photo(photo, ImageType.JPEG));
|
||||
|
||||
for (Related related : relations)
|
||||
vcard.addRelated(related);
|
||||
|
||||
// PRODID, REV
|
||||
vcard.setProductId("DAVdroid/" + Constants.APP_VERSION + " (ez-vcard/" + Ezvcard.VERSION + ")");
|
||||
@ -419,8 +447,8 @@ public class Contact extends Resource {
|
||||
// validate and print warnings
|
||||
ValidationWarnings warnings = vcard.validate(vCardVersion);
|
||||
if (!warnings.isEmpty())
|
||||
Log.w(TAG, "Created potentially invalid VCard! " + warnings);
|
||||
|
||||
Log.w(TAG, "Created potentially invalid VCard:\n" + warnings);
|
||||
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
Ezvcard
|
||||
.write(vcard)
|
||||
|
@ -27,6 +27,7 @@ import android.provider.ContactsContract.CommonDataKinds.Note;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Organization;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Photo;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Relation;
|
||||
import android.provider.ContactsContract.CommonDataKinds.SipAddress;
|
||||
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
|
||||
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
|
||||
@ -45,22 +46,27 @@ import java.io.InputStream;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
||||
import ezvcard.parameter.AddressType;
|
||||
import ezvcard.parameter.EmailType;
|
||||
import ezvcard.parameter.ImppType;
|
||||
import ezvcard.parameter.RelatedType;
|
||||
import ezvcard.parameter.TelephoneType;
|
||||
import ezvcard.property.Address;
|
||||
import ezvcard.property.Anniversary;
|
||||
import ezvcard.property.Birthday;
|
||||
import ezvcard.property.DateOrTimeProperty;
|
||||
import ezvcard.property.Impp;
|
||||
import ezvcard.property.Related;
|
||||
import ezvcard.property.Telephone;
|
||||
import lombok.Cleanup;
|
||||
|
||||
@ -201,6 +207,7 @@ public class LocalAddressBook extends LocalCollection<Contact> {
|
||||
populateCategories(c);
|
||||
populateURLs(c);
|
||||
populateEvents(c);
|
||||
populateRelations(c);
|
||||
populateSipAddress(c);
|
||||
} catch(RemoteException ex) {
|
||||
throw new LocalStorageException(ex);
|
||||
@ -573,6 +580,80 @@ public class LocalAddressBook extends LocalCollection<Contact> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void populateRelations(Contact c) throws RemoteException {
|
||||
@Cleanup Cursor cursor = providerClient.query(dataURI(),
|
||||
new String[] { Relation.NAME, Relation.TYPE, Relation.LABEL },
|
||||
Relation.RAW_CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?",
|
||||
new String[] { String.valueOf(c.getLocalID()), Relation.CONTENT_ITEM_TYPE }, null);
|
||||
|
||||
Map<String, List<RelatedType>> relations = new HashMap<>();
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
String name = cursor.getString(0);
|
||||
List<RelatedType> types = relations.get(name);
|
||||
if (types == null) {
|
||||
types = new LinkedList<>();
|
||||
relations.put(name, types);
|
||||
}
|
||||
|
||||
switch (cursor.getInt(1)) {
|
||||
case Relation.TYPE_ASSISTANT:
|
||||
types.add(RelatedType.AGENT);
|
||||
break;
|
||||
case Relation.TYPE_BROTHER:
|
||||
types.add(RelatedType.SIBLING);
|
||||
types.add(Contact.RELATED_TYPE_BROTHER);
|
||||
break;
|
||||
case Relation.TYPE_CHILD:
|
||||
types.add(RelatedType.CHILD);
|
||||
break;
|
||||
case Relation.TYPE_DOMESTIC_PARTNER:
|
||||
types.add(RelatedType.CO_RESIDENT);
|
||||
break;
|
||||
case Relation.TYPE_FATHER:
|
||||
types.add(Contact.RELATED_TYPE_FATHER);
|
||||
break;
|
||||
case Relation.TYPE_FRIEND:
|
||||
types.add(RelatedType.FRIEND);
|
||||
break;
|
||||
case Relation.TYPE_MANAGER:
|
||||
types.add(Contact.RELATED_TYPE_MANAGER);
|
||||
break;
|
||||
case Relation.TYPE_MOTHER:
|
||||
types.add(Contact.RELATED_TYPE_MOTHER);
|
||||
break;
|
||||
case Relation.TYPE_PARENT:
|
||||
types.add(RelatedType.PARENT);
|
||||
break;
|
||||
case Relation.TYPE_PARTNER:
|
||||
types.add(RelatedType.SWEETHEART);
|
||||
break;
|
||||
case Relation.TYPE_REFERRED_BY:
|
||||
types.add(Contact.RELATED_TYPE_REFERRED_BY);
|
||||
case Relation.TYPE_RELATIVE:
|
||||
types.add(RelatedType.KIN);
|
||||
break;
|
||||
case Relation.TYPE_SISTER:
|
||||
types.add(RelatedType.SIBLING);
|
||||
types.add(Contact.RELATED_TYPE_SISTER);
|
||||
break;
|
||||
case Relation.TYPE_SPOUSE:
|
||||
types.add(RelatedType.SPOUSE);
|
||||
case Relation.TYPE_CUSTOM:
|
||||
String customType = cursor.getString(2);
|
||||
if (!StringUtils.isEmpty(customType))
|
||||
types.add(RelatedType.get(customType));
|
||||
}
|
||||
}
|
||||
|
||||
for (String name : relations.keySet()) {
|
||||
Related related = new Related();
|
||||
related.setText(name);
|
||||
for (RelatedType type : relations.get(name))
|
||||
related.addType(type);
|
||||
c.getRelations().add(related);
|
||||
}
|
||||
}
|
||||
|
||||
protected void populateSipAddress(Contact c) throws RemoteException {
|
||||
@Cleanup Cursor cursor = providerClient.query(dataURI(),
|
||||
@ -659,9 +740,11 @@ public class LocalAddressBook extends LocalCollection<Contact> {
|
||||
queueOperation(buildEvent(newDataInsertBuilder(localID, backrefIdx), contact.getAnniversary(), CommonDataKinds.Event.TYPE_ANNIVERSARY));
|
||||
if (contact.getBirthDay() != null)
|
||||
queueOperation(buildEvent(newDataInsertBuilder(localID, backrefIdx), contact.getBirthDay(), CommonDataKinds.Event.TYPE_BIRTHDAY));
|
||||
|
||||
// TODO relations
|
||||
|
||||
|
||||
for (Related related : contact.getRelations())
|
||||
for (RelatedType type : related.getTypes())
|
||||
queueOperation(buildRelated(newDataInsertBuilder(localID, backrefIdx), type, related.getText()));
|
||||
|
||||
// SIP addresses are built by buildIMPP
|
||||
}
|
||||
|
||||
@ -981,7 +1064,35 @@ public class LocalAddressBook extends LocalCollection<Contact> {
|
||||
.withValue(CommonDataKinds.Event.TYPE, type)
|
||||
.withValue(CommonDataKinds.Event.START_DATE, formatter.format(date.getDate()));
|
||||
}
|
||||
|
||||
|
||||
protected Builder buildRelated(Builder builder, RelatedType type, String name) {
|
||||
int typeCode = 0;
|
||||
String typeLabel = null;
|
||||
if (type == RelatedType.CHILD)
|
||||
typeCode = Relation.TYPE_CHILD;
|
||||
else if (type == RelatedType.CO_RESIDENT)
|
||||
typeCode = Relation.TYPE_DOMESTIC_PARTNER;
|
||||
else if (type == RelatedType.FRIEND)
|
||||
typeCode = Relation.TYPE_FRIEND;
|
||||
else if (type == RelatedType.PARENT)
|
||||
typeCode = Relation.TYPE_PARENT;
|
||||
else if (type == RelatedType.SPOUSE)
|
||||
typeCode = Relation.TYPE_SPOUSE;
|
||||
else if (type == RelatedType.KIN)
|
||||
typeCode = Relation.TYPE_RELATIVE;
|
||||
else if (type == RelatedType.SWEETHEART)
|
||||
typeCode = Relation.TYPE_PARTNER;
|
||||
else {
|
||||
typeCode = Relation.TYPE_CUSTOM;
|
||||
typeLabel = type.getValue();
|
||||
}
|
||||
|
||||
return builder
|
||||
.withValue(Data.MIMETYPE, Relation.CONTENT_ITEM_TYPE)
|
||||
.withValue(Relation.TYPE, typeCode)
|
||||
.withValue(Relation.NAME, name)
|
||||
.withValue(Relation.LABEL, typeLabel);
|
||||
}
|
||||
|
||||
|
||||
/* helper methods */
|
||||
|
@ -87,6 +87,24 @@
|
||||
<Type maxOccurs="1" type="birthday" yearOptional="false" />
|
||||
<Type maxOccurs="1" type="anniversary" />
|
||||
</DataKind>
|
||||
|
||||
<DataKind kind="relationship">
|
||||
<Type type="assistant"/>
|
||||
<Type type="brother"/>
|
||||
<Type type="child"/>
|
||||
<Type type="domestic_partner"/>
|
||||
<Type type="father"/>
|
||||
<Type type="friend"/>
|
||||
<Type type="manager"/>
|
||||
<Type type="mother"/>
|
||||
<Type type="parent"/>
|
||||
<Type type="partner"/>
|
||||
<Type type="referred_by"/>
|
||||
<Type type="relative"/>
|
||||
<Type type="sister"/>
|
||||
<Type type="spouse"/>
|
||||
<Type type="custom"/>
|
||||
</DataKind>
|
||||
|
||||
<DataKind kind="sip_address" maxOccurs="1" />
|
||||
</EditSchema>
|
||||
|
Loading…
Reference in New Issue
Block a user