1
0
mirror of https://github.com/etesync/android synced 2025-02-18 02:22:08 +00:00

Version bump to 0.7.5

* account settings: show whether CardDAV server supports VCard 4.0
* CardDAV GET: ask for VCard 3.0 or VCard 4.0 (preferred) contacts
* CardDAV multiget: ask for VCard 4.0 contacts if the server supports it
* CardDAV PUT: send VCard 4.0 contacts if the server supports it
* import Apache httpclient-android rev. 1652769 correctly (hopefully fixes #491)
This commit is contained in:
Ricki Hirner 2015-05-01 00:36:12 +02:00
parent f738f74dea
commit b5c99265c3
22 changed files with 154 additions and 134 deletions

View File

@ -1,62 +0,0 @@
/*
* Copyright (c) 2013 2015 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid;
import java.io.IOException;
import java.io.InputStream;
import lombok.Cleanup;
import net.fortuna.ical4j.data.ParserException;
import android.content.res.AssetManager;
import android.test.InstrumentationTestCase;
import at.bitfire.davdroid.resource.Contact;
import ezvcard.property.Impp;
public class ContactTest extends InstrumentationTestCase {
AssetManager assetMgr;
public void setUp() {
assetMgr = getInstrumentation().getContext().getResources().getAssets();
}
public void testIMPP() throws IOException {
Contact c = parseVCard("impp.vcf");
assertEquals("test mctest", c.getDisplayName());
Impp jabber = c.getImpps().get(0);
assertNull(jabber.getProtocol());
assertEquals("test-without-valid-scheme@test.tld", jabber.getHandle());
}
public void testParseVcard3() throws IOException, ParserException {
Contact c = parseVCard("vcard3-sample1.vcf");
assertEquals("Forrest Gump", c.getDisplayName());
assertEquals("Forrest", c.getGivenName());
assertEquals("Gump", c.getFamilyName());
assertEquals(2, c.getPhoneNumbers().size());
assertEquals("(111) 555-1212", c.getPhoneNumbers().get(0).getText());
assertEquals(1, c.getEmails().size());
assertEquals("forrestgump@example.com", c.getEmails().get(0).getValue());
assertFalse(c.isStarred());
}
private Contact parseVCard(String fileName) throws IOException {
@Cleanup InputStream in = assetMgr.open(fileName, AssetManager.ACCESS_STREAMING);
Contact c = new Contact(fileName, null);
c.parseEntity(in, null);
return c;
}
}

View File

@ -7,6 +7,11 @@
*/ */
package at.bitfire.davdroid.resource; package at.bitfire.davdroid.resource;
import android.content.res.AssetManager;
import android.test.InstrumentationTestCase;
import org.apache.commons.io.IOUtils;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URI; import java.net.URI;
@ -15,16 +20,10 @@ import java.util.Arrays;
import at.bitfire.davdroid.webdav.DavException; import at.bitfire.davdroid.webdav.DavException;
import at.bitfire.davdroid.webdav.HttpException; import at.bitfire.davdroid.webdav.HttpException;
import ezvcard.VCardVersion;
import ezvcard.property.Email; import ezvcard.property.Email;
import ezvcard.property.Telephone; import ezvcard.property.Telephone;
import lombok.Cleanup; import lombok.Cleanup;
import android.content.res.AssetManager;
import android.test.InstrumentationTestCase;
import org.apache.commons.io.IOUtils;
import at.bitfire.davdroid.resource.Contact;
import at.bitfire.davdroid.resource.InvalidResourceException;
public class ContactTest extends InstrumentationTestCase { public class ContactTest extends InstrumentationTestCase {
AssetManager assetMgr; AssetManager assetMgr;
@ -32,6 +31,19 @@ public class ContactTest extends InstrumentationTestCase {
public void setUp() throws IOException, InvalidResourceException { public void setUp() throws IOException, InvalidResourceException {
assetMgr = getInstrumentation().getContext().getResources().getAssets(); assetMgr = getInstrumentation().getContext().getResources().getAssets();
} }
public void testGenerateDifferentVersions() throws Exception {
Contact c = new Contact("test.vcf", null);
// should generate VCard 3.0 by default
assertEquals("text/vcard", c.getMimeType());
assertTrue(new String(c.toEntity().toByteArray()).contains("VERSION:3.0"));
// now let's generate VCard 4.0
c.setVCardVersion(VCardVersion.V4_0);
assertEquals("text/vcard;version=4.0", c.getMimeType());
assertTrue(new String(c.toEntity().toByteArray()).contains("VERSION:4.0"));
}
public void testReferenceVCard() throws IOException, InvalidResourceException { public void testReferenceVCard() throws IOException, InvalidResourceException {
Contact c = parseVCF("reference.vcf"); Contact c = parseVCF("reference.vcf");

View File

@ -7,16 +7,16 @@
*/ */
package at.bitfire.davdroid.resource; package at.bitfire.davdroid.resource;
import android.content.res.AssetManager;
import android.test.InstrumentationTestCase;
import android.text.format.Time;
import net.fortuna.ical4j.data.ParserException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import lombok.Cleanup; import lombok.Cleanup;
import net.fortuna.ical4j.data.ParserException;
import android.content.res.AssetManager;
import android.test.InstrumentationTestCase;
import android.text.format.Time;
import at.bitfire.davdroid.resource.Event;
import at.bitfire.davdroid.resource.InvalidResourceException;
public class EventTest extends InstrumentationTestCase { public class EventTest extends InstrumentationTestCase {
AssetManager assetMgr; AssetManager assetMgr;

View File

@ -7,19 +7,13 @@
*/ */
package at.bitfire.davdroid.resource; package at.bitfire.davdroid.resource;
import java.util.Calendar;
import lombok.Cleanup;
import android.Manifest; import android.Manifest;
import android.accounts.Account; import android.accounts.Account;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.ContentProviderClient; import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentUris; import android.content.ContentUris;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
@ -30,11 +24,11 @@ import android.provider.CalendarContract.Calendars;
import android.provider.CalendarContract.Events; import android.provider.CalendarContract.Events;
import android.provider.CalendarContract.Reminders; import android.provider.CalendarContract.Reminders;
import android.test.InstrumentationTestCase; import android.test.InstrumentationTestCase;
import android.test.IsolatedContext;
import android.test.mock.MockContentResolver;
import android.util.Log; import android.util.Log;
import at.bitfire.davdroid.resource.LocalCalendar;
import at.bitfire.davdroid.resource.LocalStorageException; import java.util.Calendar;
import lombok.Cleanup;
public class LocalCalendarTest extends InstrumentationTestCase { public class LocalCalendarTest extends InstrumentationTestCase {

View File

@ -9,7 +9,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="at.bitfire.davdroid" package="at.bitfire.davdroid"
android:versionCode="59" android:versionName="0.7.3" android:versionCode="61" android:versionName="0.7.5"
android:installLocation="internalOnly"> android:installLocation="internalOnly">
<uses-sdk <uses-sdk

View File

@ -9,7 +9,7 @@ package at.bitfire.davdroid;
public class Constants { public class Constants {
public static final String public static final String
APP_VERSION = "0.7.3", APP_VERSION = "0.7.5",
ACCOUNT_TYPE = "bitfire.at.davdroid", ACCOUNT_TYPE = "bitfire.at.davdroid",
WEB_URL_HELP = "https://davdroid.bitfire.at/configuration?pk_campaign=davdroid-app", WEB_URL_HELP = "https://davdroid.bitfire.at/configuration?pk_campaign=davdroid-app",
WEB_URL_VIEW_LOGS = "https://github.com/bitfireAT/davdroid/wiki/How-to-view-the-logs"; WEB_URL_VIEW_LOGS = "https://github.com/bitfireAT/davdroid/wiki/How-to-view-the-logs";

View File

@ -7,17 +7,20 @@
*/ */
package at.bitfire.davdroid.resource; package at.bitfire.davdroid.resource;
import android.accounts.Account;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import at.bitfire.davdroid.syncadapter.AccountSettings;
import at.bitfire.davdroid.webdav.DavMultiget; import at.bitfire.davdroid.webdav.DavMultiget;
public class CalDavCalendar extends RemoteCollection<Event> { public class CalDavCalendar extends RemoteCollection<Event> {
//private final static String TAG = "davdroid.CalDavCalendar";
@Override @Override
protected String memberContentType() { protected String memberAcceptedMimeTypes()
{
return "text/calendar"; return "text/calendar";
} }

View File

@ -7,23 +7,28 @@
*/ */
package at.bitfire.davdroid.resource; package at.bitfire.davdroid.resource;
import android.accounts.Account;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import at.bitfire.davdroid.syncadapter.AccountSettings;
import at.bitfire.davdroid.webdav.DavMultiget; import at.bitfire.davdroid.webdav.DavMultiget;
import ezvcard.VCardVersion;
public class CardDavAddressBook extends RemoteCollection<Contact> { public class CardDavAddressBook extends RemoteCollection<Contact> {
//private final static String TAG = "davdroid.CardDavAddressBook"; AccountSettings accountSettings;
@Override @Override
protected String memberContentType() { protected String memberAcceptedMimeTypes() {
return Contact.MIME_TYPE; return "text/vcard;q=0.8, text/vcard;version=4.0";
} }
@Override @Override
protected DavMultiget.Type multiGetType() { protected DavMultiget.Type multiGetType() {
return DavMultiget.Type.ADDRESS_BOOK; return accountSettings.getAddressBookVCardVersion() == VCardVersion.V4_0 ?
DavMultiget.Type.ADDRESS_BOOK_V4 : DavMultiget.Type.ADDRESS_BOOK;
} }
@Override @Override
@ -32,7 +37,8 @@ public class CardDavAddressBook extends RemoteCollection<Contact> {
} }
public CardDavAddressBook(CloseableHttpClient httpClient, String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException { public CardDavAddressBook(AccountSettings settings, CloseableHttpClient httpClient, String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException {
super(httpClient, baseURL, user, password, preemptiveAuth); super(httpClient, baseURL, user, password, preemptiveAuth);
accountSettings = settings;
} }
} }

View File

@ -65,9 +65,9 @@ import lombok.ToString;
@ToString(callSuper = true) @ToString(callSuper = true)
public class Contact extends Resource { public class Contact extends Resource {
private final static String TAG = "davdroid.Contact"; private final static String TAG = "davdroid.Contact";
public final static String MIME_TYPE = "text/vcard"; @Getter @Setter protected VCardVersion vCardVersion = VCardVersion.V3_0;
public final static String public final static String
PROPERTY_STARRED = "X-DAVDROID-STARRED", PROPERTY_STARRED = "X-DAVDROID-STARRED",
PROPERTY_PHONETIC_FIRST_NAME = "X-PHONETIC-FIRST-NAME", PROPERTY_PHONETIC_FIRST_NAME = "X-PHONETIC-FIRST-NAME",
@ -110,11 +110,11 @@ public class Contact extends Resource {
/* instance methods */ /* instance methods */
public Contact(String name, String ETag) { Contact(String name, String ETag) {
super(name, ETag); super(name, ETag);
} }
public Contact(long localID, String resourceName, String eTag) { Contact(long localID, String resourceName, String eTag) {
super(localID, resourceName, eTag); super(localID, resourceName, eTag);
} }
@ -300,6 +300,14 @@ public class Contact extends Resource {
} }
} }
@Override
public String getMimeType() {
if (vCardVersion == VCardVersion.V4_0)
return "text/vcard;version=4.0";
else
return "text/vcard";
}
@Override @Override
public ByteArrayOutputStream toEntity() throws IOException { public ByteArrayOutputStream toEntity() throws IOException {
@ -409,14 +417,14 @@ public class Contact extends Resource {
vcard.setRevision(Revision.now()); vcard.setRevision(Revision.now());
// validate and print warnings // validate and print warnings
ValidationWarnings warnings = vcard.validate(VCardVersion.V3_0); ValidationWarnings warnings = vcard.validate(vCardVersion);
if (!warnings.isEmpty()) if (!warnings.isEmpty())
Log.w(TAG, "Created potentially invalid VCard! " + warnings); Log.w(TAG, "Created potentially invalid VCard! " + warnings);
ByteArrayOutputStream os = new ByteArrayOutputStream(); ByteArrayOutputStream os = new ByteArrayOutputStream();
Ezvcard Ezvcard
.write(vcard) .write(vcard)
.version(VCardVersion.V3_0) .version(vCardVersion)
.versionStrict(false) .versionStrict(false)
.prodId(false) // we provide our own PRODID .prodId(false) // we provide our own PRODID
.go(os); .go(os);

View File

@ -75,8 +75,6 @@ import lombok.Setter;
public class Event extends Resource { public class Event extends Resource {
private final static String TAG = "davdroid.Event"; private final static String TAG = "davdroid.Event";
public final static String MIME_TYPE = "text/calendar";
private final static TimeZoneRegistry tzRegistry = new DefaultTimeZoneRegistryFactory().createRegistry(); private final static TimeZoneRegistry tzRegistry = new DefaultTimeZoneRegistryFactory().createRegistry();
@Getter @Setter protected RecurrenceId recurrenceId; @Getter @Setter protected RecurrenceId recurrenceId;
@ -236,6 +234,11 @@ public class Event extends Resource {
} }
@Override
public String getMimeType() {
return "text/calendar";
}
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public ByteArrayOutputStream toEntity() throws IOException { public ByteArrayOutputStream toEntity() throws IOException {

View File

@ -123,7 +123,9 @@ public class LocalAddressBook extends LocalCollection<Contact> {
/* create/update/delete */ /* create/update/delete */
public Contact newResource(long localID, String resourceName, String eTag) { public Contact newResource(long localID, String resourceName, String eTag) {
return new Contact(localID, resourceName, eTag); Contact c = new Contact(localID, resourceName, eTag);
c.setVCardVersion(accountSettings.getAddressBookVCardVersion());
return c;
} }
public void deleteAllExceptRemoteNames(Resource[] remoteResources) { public void deleteAllExceptRemoteNames(Resource[] remoteResources) {

View File

@ -7,12 +7,12 @@
*/ */
package at.bitfire.davdroid.resource; package at.bitfire.davdroid.resource;
import android.accounts.Account;
import android.util.Log; import android.util.Log;
import net.fortuna.ical4j.model.ValidationException; import net.fortuna.ical4j.model.ValidationException;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.client.utils.URIUtilsHC4;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -21,11 +21,11 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import at.bitfire.davdroid.URIUtils; import at.bitfire.davdroid.URIUtils;
import at.bitfire.davdroid.syncadapter.AccountSettings;
import at.bitfire.davdroid.webdav.DavException; import at.bitfire.davdroid.webdav.DavException;
import at.bitfire.davdroid.webdav.DavMultiget; import at.bitfire.davdroid.webdav.DavMultiget;
import at.bitfire.davdroid.webdav.DavNoContentException; import at.bitfire.davdroid.webdav.DavNoContentException;
@ -50,8 +50,7 @@ public abstract class RemoteCollection<T extends Resource> {
URI baseURI; URI baseURI;
@Getter WebDavResource collection; @Getter WebDavResource collection;
abstract protected String memberContentType(); abstract protected String memberAcceptedMimeTypes();
abstract protected DavMultiget.Type multiGetType(); abstract protected DavMultiget.Type multiGetType();
abstract protected T newResourceSkeleton(String name, String ETag); abstract protected T newResourceSkeleton(String name, String ETag);
@ -132,14 +131,7 @@ public abstract class RemoteCollection<T extends Resource> {
public Resource get(Resource resource) throws URISyntaxException, IOException, HttpException, DavException, InvalidResourceException { public Resource get(Resource resource) throws URISyntaxException, IOException, HttpException, DavException, InvalidResourceException {
WebDavResource member = new WebDavResource(collection, resource.getName()); WebDavResource member = new WebDavResource(collection, resource.getName());
if (resource instanceof Contact) member.get(memberAcceptedMimeTypes());
member.get(Contact.MIME_TYPE);
else if (resource instanceof Event)
member.get(Event.MIME_TYPE);
else {
Log.wtf(TAG, "Should fetch something, but neither contact nor calendar");
throw new InvalidResourceException("Didn't now which MIME type to accept");
}
byte[] data = member.getContent(); byte[] data = member.getContent();
if (data == null) if (data == null)
@ -157,7 +149,7 @@ public abstract class RemoteCollection<T extends Resource> {
// returns ETag of the created resource, if returned by server // returns ETag of the created resource, if returned by server
public String add(Resource res) throws URISyntaxException, IOException, HttpException, ValidationException { public String add(Resource res) throws URISyntaxException, IOException, HttpException, ValidationException {
WebDavResource member = new WebDavResource(collection, res.getName(), res.getETag()); WebDavResource member = new WebDavResource(collection, res.getName(), res.getETag());
member.setContentType(memberContentType()); member.setContentType(res.getMimeType());
@Cleanup ByteArrayOutputStream os = res.toEntity(); @Cleanup ByteArrayOutputStream os = res.toEntity();
String eTag = member.put(os.toByteArray(), PutMode.ADD_DONT_OVERWRITE); String eTag = member.put(os.toByteArray(), PutMode.ADD_DONT_OVERWRITE);
@ -178,7 +170,7 @@ public abstract class RemoteCollection<T extends Resource> {
// returns ETag of the updated resource, if returned by server // returns ETag of the updated resource, if returned by server
public String update(Resource res) throws URISyntaxException, IOException, HttpException, ValidationException { public String update(Resource res) throws URISyntaxException, IOException, HttpException, ValidationException {
WebDavResource member = new WebDavResource(collection, res.getName(), res.getETag()); WebDavResource member = new WebDavResource(collection, res.getName(), res.getETag());
member.setContentType(memberContentType()); member.setContentType(res.getMimeType());
@Cleanup ByteArrayOutputStream os = res.toEntity(); @Cleanup ByteArrayOutputStream os = res.toEntity();
String eTag = member.put(os.toByteArray(), PutMode.UPDATE_DONT_OVERWRITE); String eTag = member.put(os.toByteArray(), PutMode.UPDATE_DONT_OVERWRITE);

View File

@ -30,7 +30,6 @@ public abstract class Resource {
@Getter @Setter protected String uid; @Getter @Setter protected String uid;
@Getter protected long localID; @Getter protected long localID;
public Resource(String name, String ETag) { public Resource(String name, String ETag) {
this.name = name; this.name = name;
this.ETag = ETag; this.ETag = ETag;
@ -50,6 +49,10 @@ public abstract class Resource {
**/ **/
public abstract void parseEntity(InputStream entity, AssetDownloader downloader) throws IOException, InvalidResourceException; public abstract void parseEntity(InputStream entity, AssetDownloader downloader) throws IOException, InvalidResourceException;
/* returns the MIME type that toEntity() will produce */
public abstract String getMimeType();
/** writes the resource data to an output stream (for instance, .vcf file for Contact) */ /** writes the resource data to an output stream (for instance, .vcf file for Contact) */
public abstract ByteArrayOutputStream toEntity() throws IOException; public abstract ByteArrayOutputStream toEntity() throws IOException;

View File

@ -67,7 +67,7 @@ public class ContactsSyncAdapterService extends Service {
try { try {
LocalCollection<?> database = new LocalAddressBook(account, provider, settings); LocalCollection<?> database = new LocalAddressBook(account, provider, settings);
RemoteCollection<?> dav = new CardDavAddressBook(httpClient, addressBookURL, userName, password, preemptive); RemoteCollection<?> dav = new CardDavAddressBook(settings, httpClient, addressBookURL, userName, password, preemptive);
Map<LocalCollection<?>, RemoteCollection<?>> map = new HashMap<LocalCollection<?>, RemoteCollection<?>>(); Map<LocalCollection<?>, RemoteCollection<?>> map = new HashMap<LocalCollection<?>, RemoteCollection<?>>();
map.put(database, dav); map.put(database, dav);

View File

@ -9,15 +9,18 @@
package at.bitfire.davdroid.ui.settings; package at.bitfire.davdroid.ui.settings;
import android.accounts.Account; import android.accounts.Account;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.preference.CheckBoxPreference; import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference; import android.preference.EditTextPreference;
import android.preference.ListPreference; import android.preference.ListPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.preference.SwitchPreference;
import at.bitfire.davdroid.R; import at.bitfire.davdroid.R;
import at.bitfire.davdroid.syncadapter.AccountSettings; import at.bitfire.davdroid.syncadapter.AccountSettings;
import ezvcard.VCardVersion;
import lombok.Setter; import lombok.Setter;
public class AccountFragment extends PreferenceFragment { public class AccountFragment extends PreferenceFragment {
@ -38,6 +41,7 @@ public class AccountFragment extends PreferenceFragment {
public void readFromAccount() { public void readFromAccount() {
final AccountSettings settings = new AccountSettings(getActivity(), account); final AccountSettings settings = new AccountSettings(getActivity(), account);
// category: authentication
final EditTextPreference prefUserName = (EditTextPreference)findPreference("username"); final EditTextPreference prefUserName = (EditTextPreference)findPreference("username");
prefUserName.setSummary(settings.getUserName()); prefUserName.setSummary(settings.getUserName());
prefUserName.setText(settings.getUserName()); prefUserName.setText(settings.getUserName());
@ -61,7 +65,7 @@ public class AccountFragment extends PreferenceFragment {
} }
}); });
final CheckBoxPreference prefPreemptive = (CheckBoxPreference)findPreference("preemptive"); final SwitchPreference prefPreemptive = (SwitchPreference)findPreference("preemptive");
prefPreemptive.setChecked(settings.getPreemptiveAuth()); prefPreemptive.setChecked(settings.getPreemptiveAuth());
prefPreemptive.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { prefPreemptive.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override @Override
@ -72,6 +76,7 @@ public class AccountFragment extends PreferenceFragment {
} }
}); });
// category: synchronization
final ListPreference prefSyncContacts = (ListPreference)findPreference("sync_interval_contacts"); final ListPreference prefSyncContacts = (ListPreference)findPreference("sync_interval_contacts");
final Long syncIntervalContacts = settings.getContactsSyncInterval(); final Long syncIntervalContacts = settings.getContactsSyncInterval();
if (syncIntervalContacts != null) { if (syncIntervalContacts != null) {
@ -113,5 +118,23 @@ public class AccountFragment extends PreferenceFragment {
prefSyncCalendars.setEnabled(false); prefSyncCalendars.setEnabled(false);
prefSyncCalendars.setSummary(R.string.settings_sync_summary_not_available); prefSyncCalendars.setSummary(R.string.settings_sync_summary_not_available);
} }
// category: address book
final CheckBoxPreference prefVCard4 = (CheckBoxPreference) findPreference("vcard4_support");
if (settings.getAddressBookURL() != null) { // does this account even have an address book?
final VCardVersion vCardVersion = settings.getAddressBookVCardVersion();
prefVCard4.setChecked(vCardVersion == VCardVersion.V4_0);
prefVCard4.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// don't change the value (it's not really a setting, only a display)
return false;
}
});
} else {
// account doesn't have an adress book, disable contact settings
prefVCard4.setEnabled(false);
}
} }
} }

View File

@ -18,6 +18,7 @@ import java.util.List;
public class DavMultiget { public class DavMultiget {
public enum Type { public enum Type {
ADDRESS_BOOK, ADDRESS_BOOK,
ADDRESS_BOOK_V4,
CALENDAR CALENDAR
} }
@ -29,15 +30,24 @@ public class DavMultiget {
public static DavMultiget newRequest(Type type, String names[]) { public static DavMultiget newRequest(Type type, String names[]) {
DavMultiget multiget = (type == Type.ADDRESS_BOOK) ? new DavAddressbookMultiget() : new DavCalendarMultiget(); DavMultiget multiget = (type == Type.CALENDAR) ? new DavCalendarMultiget() : new DavAddressbookMultiget();
multiget.prop = new DavProp(); multiget.prop = new DavProp();
multiget.prop.getetag = new DavProp.GetETag(); multiget.prop.getetag = new DavProp.GetETag();
if (type == Type.ADDRESS_BOOK) switch (type) {
multiget.prop.addressData = new DavProp.AddressData(); case ADDRESS_BOOK:
else if (type == Type.CALENDAR) multiget.prop.addressData = new DavProp.AddressData();
multiget.prop.calendarData = new DavProp.CalendarData(); break;
case ADDRESS_BOOK_V4:
DavProp.AddressData addressData = new DavProp.AddressData();
addressData.setContentType("text/vcard");
addressData.setVersion("4.0");
multiget.prop.addressData = addressData;
break;
case CALENDAR:
multiget.prop.calendarData = new DavProp.CalendarData();
}
multiget.hrefs = new ArrayList<DavHref>(names.length); multiget.hrefs = new ArrayList<DavHref>(names.length);
for (String name : names) for (String name : names)

View File

@ -17,6 +17,7 @@ import org.simpleframework.xml.Text;
import java.util.List; import java.util.List;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
@Namespace(prefix="D",reference="DAV:") @Namespace(prefix="D",reference="DAV:")
@Root(strict=false) @Root(strict=false)
@ -199,6 +200,12 @@ public class DavProp {
@Namespace(prefix="CD",reference="urn:ietf:params:xml:ns:carddav") @Namespace(prefix="CD",reference="urn:ietf:params:xml:ns:carddav")
public static class AddressData { public static class AddressData {
@Attribute(name="content-type", required=false)
@Getter @Setter String contentType;
@Attribute(required=false)
@Getter @Setter String version;
@Text(required=false) @Text(required=false)
@Getter String vcard; @Getter String vcard;
} }

View File

@ -335,9 +335,9 @@ public class WebDavResource {
/* resource operations */ /* resource operations */
public void get(String acceptedType) throws URISyntaxException, IOException, HttpException, DavException { public void get(String acceptedMimeTypes) throws URISyntaxException, IOException, HttpException, DavException {
HttpGetHC4 get = new HttpGetHC4(location); HttpGetHC4 get = new HttpGetHC4(location);
get.addHeader("Accept", acceptedType); get.addHeader("Accept", acceptedMimeTypes);
@Cleanup CloseableHttpResponse response = httpClient.execute(get, context); @Cleanup CloseableHttpResponse response = httpClient.execute(get, context);
checkResponse(response); checkResponse(response);

View File

@ -137,6 +137,10 @@
<item>Alle 4 Stunden</item> <item>Alle 4 Stunden</item>
<item>Täglich</item> <item>Täglich</item>
</string-array> </string-array>
<string name="settings_carddav">Adressbuch</string>
<string name="settings_carddav_vcard4_support">VCard 4.0-Unterstützung</string>
<string name="settings_carddav_vcard4_supported">Kontakte werden als VCard 4.0 gesendet</string>
<string name="settings_carddav_vcard4_not_supported">Kontakte werden als VCard 3.0 gesendet</string>
<string name="setup_select_collections">DAVdroid: Ordner auswählen</string> <string name="setup_select_collections">DAVdroid: Ordner auswählen</string>
<string name="setup_neither_caldav_nor_carddav">An dieser Adresse konnte kein CalDAV- oder CardDAV-Dienst gefunden werden.</string> <string name="setup_neither_caldav_nor_carddav">An dieser Adresse konnte kein CalDAV- oder CardDAV-Dienst gefunden werden.</string>

View File

@ -151,6 +151,10 @@
<item>Every 4 hours</item> <item>Every 4 hours</item>
<item>Once a day</item> <item>Once a day</item>
</string-array> </string-array>
<string name="settings_carddav">Address book</string>
<string name="settings_carddav_vcard4_support">VCard 4.0 support</string>
<string name="settings_carddav_vcard4_supported">Contacts are sent in VCard 4.0 format</string>
<string name="settings_carddav_vcard4_not_supported">Contacts are sent in VCard 3.0 format</string>
<string name="setup_select_collections">DAVdroid: Select collections</string> <string name="setup_select_collections">DAVdroid: Select collections</string>
<string name="setup_neither_caldav_nor_carddav">No CalDAV-/CardDAV service is available at this location.</string> <string name="setup_neither_caldav_nor_carddav">No CalDAV-/CardDAV service is available at this location.</string>

View File

@ -25,7 +25,7 @@
android:summary="@string/settings_password_summary" android:summary="@string/settings_password_summary"
android:dialogTitle="@string/settings_enter_password" /> android:dialogTitle="@string/settings_enter_password" />
<CheckBoxPreference <SwitchPreference
android:key="preemptive" android:key="preemptive"
android:persistent="false" android:persistent="false"
android:title="@string/settings_preemptive" android:title="@string/settings_preemptive"
@ -52,4 +52,15 @@
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/settings_carddav">
<CheckBoxPreference
android:key="vcard4_support"
android:title="@string/settings_carddav_vcard4_support"
android:persistent="false"
android:summaryOn="@string/settings_carddav_vcard4_supported"
android:summaryOff="@string/settings_carddav_vcard4_not_supported" />
</PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>

View File

@ -282,7 +282,7 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
} }
} }
@TargetApi(17) @TargetApi(9)
public Socket createLayeredSocket( public Socket createLayeredSocket(
final Socket socket, final Socket socket,
final String target, final String target,
@ -319,7 +319,7 @@ public class SSLConnectionSocketFactory implements LayeredConnectionSocketFactor
prepareSocket(sslsock); prepareSocket(sslsock);
// Android specific code to enable SNI // Android specific code to enable SNI
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
if (Log.isLoggable(TAG, Log.DEBUG)) { if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Enabling SNI for " + target); Log.d(TAG, "Enabling SNI for " + target);
} }