1
0
mirror of https://github.com/etesync/android synced 2024-11-26 09:58:11 +00:00

Library updates

* use ical4j/2.0.x instead of 1.0.x (thanks @benfortuna)
* use Apache Commons 3.x instead of 2.x
* code optimizations
This commit is contained in:
Ricki Hirner 2015-06-14 19:24:40 +02:00
parent c8cfbd6b07
commit a796a1e9b3
51 changed files with 209 additions and 384 deletions

View File

@ -32,6 +32,7 @@ android {
} }
packagingOptions { packagingOptions {
exclude 'LICENSE'
exclude 'META-INF/LICENSE.txt' exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt' exclude 'META-INF/NOTICE.txt'
} }
@ -43,12 +44,15 @@ configurations.all {
dependencies { dependencies {
// Apache Commons // Apache Commons
compile 'commons-lang:commons-lang:2.6' compile 'org.apache.commons:commons-lang3:3.4'
compile 'commons-io:commons-io:2.4' compile 'commons-io:commons-io:2.4'
// Lombok for useful @helpers // Lombok for useful @helpers
provided 'org.projectlombok:lombok:1.16.4' provided 'org.projectlombok:lombok:1.16.4'
// ical4j for parsing/generating iCalendars // ical4j for parsing/generating iCalendars
compile 'org.mnode.ical4j:ical4j:1.0.6' compile('org.mnode.ical4j:ical4j:2.0-alpha1') {
// we don't need content builders, see https://github.com/ical4j/ical4j/wiki/Groovy
exclude group: 'org.codehaus.groovy', module: 'groovy-all'
}
// ez-vcard for parsing/generating VCards // ez-vcard for parsing/generating VCards
compile('com.googlecode.ez-vcard:ez-vcard:0.9.6') { compile('com.googlecode.ez-vcard:ez-vcard:0.9.6') {
// hCard functionality not needed // hCard functionality not needed

View File

@ -73,14 +73,14 @@ public class ContactTest extends InstrumentationTestCase {
assertTrue(Arrays.equals(c.getPhoto(), expectedPhoto)); assertTrue(Arrays.equals(c.getPhoto(), expectedPhoto));
} }
public void testParseInvalidUnknownProperties() throws IOException, InvalidResourceException { public void testParseInvalidUnknownProperties() throws IOException {
Contact c = parseVCF("invalid-unknown-properties.vcf"); Contact c = parseVCF("invalid-unknown-properties.vcf");
assertEquals("VCard with invalid unknown properties", c.getDisplayName()); assertEquals("VCard with invalid unknown properties", c.getDisplayName());
assertNull(c.getUnknownProperties()); assertNull(c.getUnknownProperties());
} }
protected Contact parseVCF(String fname) throws IOException, InvalidResourceException { protected Contact parseVCF(String fname) throws IOException {
@Cleanup InputStream in = assetMgr.open(fname, AssetManager.ACCESS_STREAMING); @Cleanup InputStream in = assetMgr.open(fname, AssetManager.ACCESS_STREAMING);
Contact c = new Contact(fname, null); Contact c = new Contact(fname, null);
c.parseEntity(in, new Resource.AssetDownloader() { c.parseEntity(in, new Resource.AssetDownloader() {

View File

@ -53,7 +53,7 @@ public class LocalCalendarTest extends InstrumentationTestCase {
Context targetContext; Context targetContext;
ContentProviderClient providerClient; ContentProviderClient providerClient;
Account testAccount = new Account(calendarName, accountType); final Account testAccount = new Account(calendarName, accountType);
Uri calendarURI; Uri calendarURI;
LocalCalendar testCalendar; LocalCalendar testCalendar;
@ -69,7 +69,7 @@ public class LocalCalendarTest extends InstrumentationTestCase {
build(); build();
} }
private long insertNewEvent() throws LocalStorageException, RemoteException { private long insertNewEvent() throws RemoteException {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(Events.CALENDAR_ID, testCalendar.getId()); values.put(Events.CALENDAR_ID, testCalendar.getId());
values.put(Events.TITLE, "Test Event"); values.put(Events.TITLE, "Test Event");

View File

@ -13,14 +13,12 @@ import android.test.InstrumentationTestCase;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGetHC4; import org.apache.http.client.methods.HttpGetHC4;
import org.apache.http.client.methods.HttpPostHC4; import org.apache.http.client.methods.HttpPostHC4;
import org.apache.http.client.methods.HttpRequestBaseHC4;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import at.bitfire.davdroid.TestConstants; import at.bitfire.davdroid.TestConstants;
import lombok.Cleanup;
public class DavHttpClientTest extends InstrumentationTestCase { public class DavHttpClientTest extends InstrumentationTestCase {
final static URI testCookieURI = TestConstants.roboHydra.resolve("/dav/testCookieStore"); final static URI testCookieURI = TestConstants.roboHydra.resolve("/dav/testCookieStore");

View File

@ -25,7 +25,7 @@ import at.bitfire.davdroid.TestConstants;
public class DavRedirectStrategyTest extends TestCase { public class DavRedirectStrategyTest extends TestCase {
CloseableHttpClient httpClient; CloseableHttpClient httpClient;
DavRedirectStrategy strategy = DavRedirectStrategy.INSTANCE; final DavRedirectStrategy strategy = DavRedirectStrategy.INSTANCE;
@Override @Override
protected void setUp() { protected void setUp() {

View File

@ -12,8 +12,8 @@ import android.util.Log;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.HttpHost; import org.apache.http.HttpHost;
import java.io.IOException; import java.io.IOException;
@ -29,7 +29,7 @@ import lombok.Cleanup;
public class TlsSniSocketFactoryTest extends TestCase { public class TlsSniSocketFactoryTest extends TestCase {
private static final String TAG = "davdroid.TlsSniSocketFactoryTest"; private static final String TAG = "davdroid.TlsSniSocketFactoryTest";
TlsSniSocketFactory factory = TlsSniSocketFactory.getSocketFactory(); final TlsSniSocketFactory factory = TlsSniSocketFactory.getSocketFactory();
private InetSocketAddress sampleTlsEndpoint; private InetSocketAddress sampleTlsEndpoint;
@ -75,7 +75,7 @@ public class TlsSniSocketFactoryTest extends TestCase {
} }
public void testProtocolVersions() throws IOException { public void testProtocolVersions() throws IOException {
String enabledProtocols[] = factory.protocols; String enabledProtocols[] = TlsSniSocketFactory.protocols;
// SSL (all versions) should be disabled // SSL (all versions) should be disabled
for (String protocol : enabledProtocols) for (String protocol : enabledProtocols)
assertFalse(protocol.contains("SSL")); assertFalse(protocol.contains("SSL"));

View File

@ -28,9 +28,7 @@ import lombok.Cleanup;
// tests require running robohydra! // tests require running robohydra!
public class WebDavResourceTest extends InstrumentationTestCase { public class WebDavResourceTest extends InstrumentationTestCase {
static byte[] SAMPLE_CONTENT = new byte[] { 1, 2, 3, 4, 5 }; final static byte[] SAMPLE_CONTENT = new byte[] { 1, 2, 3, 4, 5 };
final static String PATH_SIMPLE_FILE = "collection/new.file";
AssetManager assetMgr; AssetManager assetMgr;
CloseableHttpClient httpClient; CloseableHttpClient httpClient;

View File

@ -7,6 +7,7 @@
*/ */
package at.bitfire.davdroid; package at.bitfire.davdroid;
import net.fortuna.ical4j.model.Calendar;
import net.fortuna.ical4j.model.property.ProdId; import net.fortuna.ical4j.model.property.ProdId;
public class Constants { public class Constants {
@ -16,5 +17,5 @@ public class Constants {
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";
public static final ProdId ICAL_PRODID = new ProdId("-//bitfire web engineering//DAVdroid " + Constants.APP_VERSION + " (ical4j 1.0.x)//EN"); public static final ProdId ICAL_PRODID = new ProdId("-//bitfire web engineering//DAVdroid " + Constants.APP_VERSION + " (ical4j 2.0-alpha1)//EN");
} }

View File

@ -15,7 +15,7 @@ import net.fortuna.ical4j.model.DefaultTimeZoneRegistryFactory;
import net.fortuna.ical4j.model.TimeZone; import net.fortuna.ical4j.model.TimeZone;
import net.fortuna.ical4j.model.TimeZoneRegistry; import net.fortuna.ical4j.model.TimeZoneRegistry;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.SimpleTimeZone; import java.util.SimpleTimeZone;

View File

@ -9,11 +9,6 @@ package at.bitfire.davdroid;
import android.util.Log; import android.util.Log;
import org.apache.commons.codec.EncoderException;
import org.apache.commons.codec.net.URLCodec;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;

View File

@ -7,7 +7,6 @@
*/ */
package at.bitfire.davdroid.resource; package at.bitfire.davdroid.resource;
import android.accounts.Account;
import android.util.Log; import android.util.Log;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
@ -17,7 +16,6 @@ import org.simpleframework.xml.core.Persister;
import java.io.StringWriter; import java.io.StringWriter;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import at.bitfire.davdroid.syncadapter.AccountSettings;
import at.bitfire.davdroid.webdav.DavCalendarQuery; import at.bitfire.davdroid.webdav.DavCalendarQuery;
import at.bitfire.davdroid.webdav.DavCompFilter; import at.bitfire.davdroid.webdav.DavCompFilter;
import at.bitfire.davdroid.webdav.DavFilter; import at.bitfire.davdroid.webdav.DavFilter;

View File

@ -7,8 +7,6 @@
*/ */
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;

View File

@ -9,20 +9,14 @@ package at.bitfire.davdroid.resource;
import android.util.Log; import android.util.Log;
import net.fortuna.ical4j.model.property.ProdId; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang.StringUtils;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import at.bitfire.davdroid.Constants; import at.bitfire.davdroid.Constants;
@ -30,7 +24,6 @@ import ezvcard.Ezvcard;
import ezvcard.VCard; import ezvcard.VCard;
import ezvcard.VCardVersion; import ezvcard.VCardVersion;
import ezvcard.ValidationWarnings; import ezvcard.ValidationWarnings;
import ezvcard.Warning;
import ezvcard.parameter.EmailType; import ezvcard.parameter.EmailType;
import ezvcard.parameter.ImageType; import ezvcard.parameter.ImageType;
import ezvcard.parameter.RelatedType; import ezvcard.parameter.RelatedType;
@ -59,8 +52,6 @@ import ezvcard.property.Telephone;
import ezvcard.property.Title; import ezvcard.property.Title;
import ezvcard.property.Uid; import ezvcard.property.Uid;
import ezvcard.property.Url; import ezvcard.property.Url;
import ezvcard.property.VCardProperty;
import ezvcard.util.ListMultimap;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
@ -265,7 +256,7 @@ public class Contact extends Resource {
} }
// NOTE // NOTE
List<String> notes = new LinkedList<String>(); List<String> notes = new LinkedList<>();
for (Note note : vcard.getNotes()) for (Note note : vcard.getNotes())
notes.add(note.getValue()); notes.add(note.getValue());
if (!notes.isEmpty()) if (!notes.isEmpty())
@ -420,7 +411,7 @@ public class Contact extends Resource {
// CATEGORY // CATEGORY
if (!categories.isEmpty()) if (!categories.isEmpty())
vcard.setCategories(categories.toArray(new String[0])); vcard.setCategories(categories.toArray(new String[categories.size()]));
// URL // URL
for (String url : URLs) for (String url : URLs)

View File

@ -9,7 +9,6 @@ package at.bitfire.davdroid.resource;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
import android.widget.Toast;
import org.apache.http.HttpException; import org.apache.http.HttpException;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
@ -22,7 +21,6 @@ import org.xbill.DNS.Type;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.LinkedList; import java.util.LinkedList;
@ -40,8 +38,8 @@ import ezvcard.VCardVersion;
public class DavResourceFinder implements Closeable { public class DavResourceFinder implements Closeable {
private final static String TAG = "davdroid.ResourceFinder"; private final static String TAG = "davdroid.ResourceFinder";
protected Context context; final protected Context context;
protected CloseableHttpClient httpClient; final protected CloseableHttpClient httpClient;
public DavResourceFinder(Context context) { public DavResourceFinder(Context context) {
@ -187,10 +185,9 @@ public class DavResourceFinder implements Closeable {
* @param serviceName Service name ("carddav" or "caldav") * @param serviceName Service name ("carddav" or "caldav")
* @return Initial service URL (HTTP/HTTPS), without user credentials * @return Initial service URL (HTTP/HTTPS), without user credentials
* @throws URISyntaxException when the user-given URI is invalid * @throws URISyntaxException when the user-given URI is invalid
* @throws MalformedURLException when the user-given URI is invalid
*/ */
public URI getInitialContextURL(ServerInfo serverInfo, String serviceName) throws URISyntaxException, MalformedURLException { public URI getInitialContextURL(ServerInfo serverInfo, String serviceName) throws URISyntaxException {
String scheme = null, String scheme,
domain; domain;
int port = -1; int port = -1;
String path = "/"; String path = "/";

View File

@ -38,7 +38,6 @@ import net.fortuna.ical4j.model.property.ExRule;
import net.fortuna.ical4j.model.property.LastModified; import net.fortuna.ical4j.model.property.LastModified;
import net.fortuna.ical4j.model.property.Location; import net.fortuna.ical4j.model.property.Location;
import net.fortuna.ical4j.model.property.Organizer; import net.fortuna.ical4j.model.property.Organizer;
import net.fortuna.ical4j.model.property.ProdId;
import net.fortuna.ical4j.model.property.RDate; import net.fortuna.ical4j.model.property.RDate;
import net.fortuna.ical4j.model.property.RRule; import net.fortuna.ical4j.model.property.RRule;
import net.fortuna.ical4j.model.property.RecurrenceId; import net.fortuna.ical4j.model.property.RecurrenceId;
@ -51,19 +50,15 @@ import net.fortuna.ical4j.util.CompatibilityHints;
import net.fortuna.ical4j.util.SimpleHostInfo; import net.fortuna.ical4j.util.SimpleHostInfo;
import net.fortuna.ical4j.util.UidGenerator; import net.fortuna.ical4j.util.UidGenerator;
import org.apache.commons.lang.StringUtils;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.StringReader; import java.io.StringReader;
import java.util.Calendar; import java.util.Calendar;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.SimpleTimeZone;
import java.util.TimeZone; import java.util.TimeZone;
import at.bitfire.davdroid.Constants; import at.bitfire.davdroid.Constants;
@ -98,9 +93,9 @@ public class Event extends Resource {
@Getter @Setter protected boolean opaque; @Getter @Setter protected boolean opaque;
@Getter @Setter protected Organizer organizer; @Getter @Setter protected Organizer organizer;
@Getter protected List<Attendee> attendees = new LinkedList<Attendee>(); @Getter protected List<Attendee> attendees = new LinkedList<>();
@Getter protected List<VAlarm> alarms = new LinkedList<VAlarm>(); @Getter protected List<VAlarm> alarms = new LinkedList<>();
static { static {
CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_UNFOLDING, true); CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_UNFOLDING, true);
@ -201,10 +196,10 @@ public class Event extends Resource {
} }
rrule = (RRule)event.getProperty(Property.RRULE); rrule = (RRule)event.getProperty(Property.RRULE);
for (RDate rdate : (Iterable<RDate>)event.getProperties(Property.RDATE)) for (RDate rdate : (List<RDate>)(List<?>)event.getProperties(Property.RDATE))
rdates.add(rdate); rdates.add(rdate);
exrule = (ExRule)event.getProperty(Property.EXRULE); exrule = (ExRule)event.getProperty(Property.EXRULE);
for (ExDate exdate : (Iterable<ExDate>)event.getProperties(Property.EXDATE)) for (ExDate exdate : (List<ExDate>)(List<?>)event.getProperties(Property.EXDATE))
exdates.add(exdate); exdates.add(exdate);
if (event.getSummary() != null) if (event.getSummary() != null)
@ -218,7 +213,7 @@ public class Event extends Resource {
opaque = event.getTransparency() != Transp.TRANSPARENT; opaque = event.getTransparency() != Transp.TRANSPARENT;
organizer = event.getOrganizer(); organizer = event.getOrganizer();
for (Attendee attendee : (Iterable<Attendee>)event.getProperties(Property.ATTENDEE)) for (Attendee attendee : (List<Attendee>)(List<?>)event.getProperties(Property.ATTENDEE))
attendees.add(attendee); attendees.add(attendee);
Clazz classification = event.getClassification(); Clazz classification = event.getClassification();

View File

@ -41,21 +41,17 @@ import android.provider.ContactsContract.RawContacts;
import android.util.Log; import android.util.Log;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang.WordUtils;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Set; import java.util.Set;
import at.bitfire.davdroid.syncadapter.AccountSettings; import at.bitfire.davdroid.syncadapter.AccountSettings;
@ -64,7 +60,6 @@ import ezvcard.parameter.EmailType;
import ezvcard.parameter.ImppType; import ezvcard.parameter.ImppType;
import ezvcard.parameter.RelatedType; import ezvcard.parameter.RelatedType;
import ezvcard.parameter.TelephoneType; import ezvcard.parameter.TelephoneType;
import ezvcard.parameter.VCardParameter;
import ezvcard.property.Address; import ezvcard.property.Address;
import ezvcard.property.Anniversary; import ezvcard.property.Anniversary;
import ezvcard.property.Birthday; import ezvcard.property.Birthday;
@ -81,7 +76,7 @@ public class LocalAddressBook extends LocalCollection<Contact> {
protected final static String COLUMN_UNKNOWN_PROPERTIES = RawContacts.SYNC3; protected final static String COLUMN_UNKNOWN_PROPERTIES = RawContacts.SYNC3;
protected AccountSettings accountSettings; final protected AccountSettings accountSettings;
/* database fields */ /* database fields */
@ -138,7 +133,7 @@ public class LocalAddressBook extends LocalCollection<Contact> {
return c; return c;
} }
public void deleteAllExceptRemoteNames(Resource[] remoteResources) { public int deleteAllExceptRemoteNames(Resource[] remoteResources) throws LocalStorageException {
String where; String where;
if (remoteResources.length != 0) { if (remoteResources.length != 0) {
@ -149,15 +144,16 @@ public class LocalAddressBook extends LocalCollection<Contact> {
} else } else
where = entryColumnRemoteName() + " IS NOT NULL"; where = entryColumnRemoteName() + " IS NOT NULL";
Builder builder = ContentProviderOperation.newDelete(entriesURI()).withSelection(where, null); try {
pendingOperations.add(builder return providerClient.delete(entriesURI(), where, null);
.withYieldAllowed(true) } catch (RemoteException e) {
.build()); throw new LocalStorageException("Couldn't delete contacts locally", e);
}
} }
@Override @Override
public void commit() throws LocalStorageException { public int commit() throws LocalStorageException {
super.commit(); int affected = super.commit();
// update group details for groups we have just created // update group details for groups we have just created
Uri groupsUri = syncAdapterURI(Groups.CONTENT_URI); Uri groupsUri = syncAdapterURI(Groups.CONTENT_URI);
@ -175,11 +171,13 @@ public class LocalAddressBook extends LocalCollection<Contact> {
.withValue(Groups.TITLE, sourceID) .withValue(Groups.TITLE, sourceID)
.withValue(Groups.GROUP_VISIBLE, 1) .withValue(Groups.GROUP_VISIBLE, 1)
.build()); .build());
super.commit(); affected += super.commit();
} }
} catch (RemoteException e) { } catch (RemoteException e) {
throw new LocalStorageException("Couldn't update group names", e); throw new LocalStorageException("Couldn't update group names", e);
} }
return affected;
} }
@ -542,11 +540,11 @@ public class LocalAddressBook extends LocalCollection<Contact> {
Log.d(TAG, "Group not found (maybe deleted)"); Log.d(TAG, "Group not found (maybe deleted)");
} }
protected void populateURL(Contact c, ContentValues row) throws RemoteException { protected void populateURL(Contact c, ContentValues row) {
c.getURLs().add(row.getAsString(Website.URL)); c.getURLs().add(row.getAsString(Website.URL));
} }
protected void populateEvent(Contact c, ContentValues row) throws RemoteException { protected void populateEvent(Contact c, ContentValues row) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd", Locale.US); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
try { try {
Date date = formatter.parse(row.getAsString(CommonDataKinds.Event.START_DATE)); Date date = formatter.parse(row.getAsString(CommonDataKinds.Event.START_DATE));
@ -563,7 +561,7 @@ public class LocalAddressBook extends LocalCollection<Contact> {
} }
} }
protected void populateRelation(Contact c, ContentValues row) throws RemoteException { protected void populateRelation(Contact c, ContentValues row) {
String name = row.getAsString(Relation.NAME); String name = row.getAsString(Relation.NAME);
// don't process empty relations // don't process empty relations
@ -634,7 +632,7 @@ public class LocalAddressBook extends LocalCollection<Contact> {
} }
} }
protected void populateSipAddress(Contact c, ContentValues row) throws RemoteException { protected void populateSipAddress(Contact c, ContentValues row) {
try { try {
Impp impp = new Impp("sip:" + row.getAsString(SipAddress.SIP_ADDRESS)); Impp impp = new Impp("sip:" + row.getAsString(SipAddress.SIP_ADDRESS));
switch (row.getAsInteger(SipAddress.TYPE)) { switch (row.getAsInteger(SipAddress.TYPE)) {
@ -971,11 +969,11 @@ public class LocalAddressBook extends LocalCollection<Contact> {
lineLocality = StringUtils.join(new String[] { address.getPostalCode(), address.getLocality() }, " "); lineLocality = StringUtils.join(new String[] { address.getPostalCode(), address.getLocality() }, " ");
List<String> lines = new LinkedList<>(); List<String> lines = new LinkedList<>();
if (lineStreet != null) if (StringUtils.isNotBlank(lineStreet))
lines.add(lineStreet); lines.add(lineStreet);
if (address.getRegion() != null && !address.getRegion().isEmpty()) if (address.getRegion() != null && !address.getRegion().isEmpty())
lines.add(address.getRegion()); lines.add(address.getRegion());
if (lineLocality != null) if (StringUtils.isNotBlank(lineLocality))
lines.add(lineLocality); lines.add(lineLocality);
formattedAddress = StringUtils.join(lines, "\n"); formattedAddress = StringUtils.join(lines, "\n");
@ -1088,7 +1086,7 @@ public class LocalAddressBook extends LocalCollection<Contact> {
String lowerCase = StringUtils.lowerCase(xname, Locale.US), String lowerCase = StringUtils.lowerCase(xname, Locale.US),
withoutPrefix = StringUtils.removeStart(lowerCase, "x-"), withoutPrefix = StringUtils.removeStart(lowerCase, "x-"),
withSpaces = StringUtils.replace(withoutPrefix, "_", " "); withSpaces = StringUtils.replace(withoutPrefix, "_", " ");
return WordUtils.capitalize(withSpaces); return StringUtils.capitalize(withSpaces);
} }
} }

View File

@ -28,21 +28,14 @@ import android.provider.CalendarContract.Attendees;
import android.provider.CalendarContract.Calendars; 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.provider.ContactsContract;
import android.util.Log; import android.util.Log;
import net.fortuna.ical4j.model.Date; import net.fortuna.ical4j.model.Date;
import net.fortuna.ical4j.model.DateList;
import net.fortuna.ical4j.model.DateTime; import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.Dur; import net.fortuna.ical4j.model.Dur;
import net.fortuna.ical4j.model.Parameter; import net.fortuna.ical4j.model.Parameter;
import net.fortuna.ical4j.model.ParameterList; import net.fortuna.ical4j.model.ParameterList;
import net.fortuna.ical4j.model.Period;
import net.fortuna.ical4j.model.PeriodList;
import net.fortuna.ical4j.model.PropertyList; import net.fortuna.ical4j.model.PropertyList;
import net.fortuna.ical4j.model.TimeZone;
import net.fortuna.ical4j.model.TimeZoneRegistry;
import net.fortuna.ical4j.model.TimeZoneRegistryFactory;
import net.fortuna.ical4j.model.component.VAlarm; import net.fortuna.ical4j.model.component.VAlarm;
import net.fortuna.ical4j.model.parameter.Cn; import net.fortuna.ical4j.model.parameter.Cn;
import net.fortuna.ical4j.model.parameter.CuType; import net.fortuna.ical4j.model.parameter.CuType;
@ -51,7 +44,6 @@ import net.fortuna.ical4j.model.parameter.Role;
import net.fortuna.ical4j.model.property.Action; import net.fortuna.ical4j.model.property.Action;
import net.fortuna.ical4j.model.property.Attendee; import net.fortuna.ical4j.model.property.Attendee;
import net.fortuna.ical4j.model.property.DateListProperty; import net.fortuna.ical4j.model.property.DateListProperty;
import net.fortuna.ical4j.model.property.DateProperty;
import net.fortuna.ical4j.model.property.Description; import net.fortuna.ical4j.model.property.Description;
import net.fortuna.ical4j.model.property.Duration; import net.fortuna.ical4j.model.property.Duration;
import net.fortuna.ical4j.model.property.ExDate; import net.fortuna.ical4j.model.property.ExDate;
@ -61,19 +53,14 @@ import net.fortuna.ical4j.model.property.RDate;
import net.fortuna.ical4j.model.property.RRule; import net.fortuna.ical4j.model.property.RRule;
import net.fortuna.ical4j.model.property.RecurrenceId; import net.fortuna.ical4j.model.property.RecurrenceId;
import net.fortuna.ical4j.model.property.Status; import net.fortuna.ical4j.model.property.Status;
import net.fortuna.ical4j.util.TimeZones;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL;
import java.text.ParseException; import java.text.ParseException;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import at.bitfire.davdroid.DAVUtils; import at.bitfire.davdroid.DAVUtils;
import at.bitfire.davdroid.DateUtils; import at.bitfire.davdroid.DateUtils;
@ -91,7 +78,7 @@ public class LocalCalendar extends LocalCollection<Event> {
@Getter protected String url; @Getter protected String url;
@Getter protected long id; @Getter protected long id;
protected static String COLLECTION_COLUMN_CTAG = Calendars.CAL_SYNC1; protected static final String COLLECTION_COLUMN_CTAG = Calendars.CAL_SYNC1;
/* database fields */ /* database fields */
@ -118,7 +105,7 @@ public class LocalCalendar extends LocalCollection<Event> {
@SuppressLint("InlinedApi") @SuppressLint("InlinedApi")
public static Uri create(Account account, ContentResolver resolver, ServerInfo.ResourceInfo info) throws LocalStorageException { public static Uri create(Account account, ContentResolver resolver, ServerInfo.ResourceInfo info) throws LocalStorageException {
final ContentProviderClient client = resolver.acquireContentProviderClient(CalendarContract.AUTHORITY); @Cleanup("release") final ContentProviderClient client = resolver.acquireContentProviderClient(CalendarContract.AUTHORITY);
if (client == null) if (client == null)
throw new LocalStorageException("No Calendar Provider found (Calendar app disabled?)"); throw new LocalStorageException("No Calendar Provider found (Calendar app disabled?)");
@ -168,7 +155,7 @@ public class LocalCalendar extends LocalCollection<Event> {
return calendars.toArray(new LocalCalendar[calendars.size()]); return calendars.toArray(new LocalCalendar[calendars.size()]);
} }
public LocalCalendar(Account account, ContentProviderClient providerClient, long id, String url) throws RemoteException { public LocalCalendar(Account account, ContentProviderClient providerClient, long id, String url) {
super(account, providerClient); super(account, providerClient);
this.id = id; this.id = id;
this.url = url; this.url = url;
@ -229,7 +216,7 @@ public class LocalCalendar extends LocalCollection<Event> {
return new Event(localID, resourceName, eTag); return new Event(localID, resourceName, eTag);
} }
public void deleteAllExceptRemoteNames(Resource[] remoteResources) { public int deleteAllExceptRemoteNames(Resource[] remoteResources) throws LocalStorageException {
List<String> sqlFileNames = new LinkedList<>(); List<String> sqlFileNames = new LinkedList<>();
for (Resource res : remoteResources) for (Resource res : remoteResources)
sqlFileNames.add(DatabaseUtils.sqlEscapeString(res.getName())); sqlFileNames.add(DatabaseUtils.sqlEscapeString(res.getName()));
@ -256,6 +243,7 @@ public class LocalCalendar extends LocalCollection<Event> {
.withYieldAllowed(true) .withYieldAllowed(true)
.build() .build()
); );
return commit();
} }
@Override @Override
@ -454,7 +442,7 @@ public class LocalCalendar extends LocalCollection<Event> {
} }
} }
void populateAttendee(Event event, ContentValues values) throws RemoteException { void populateAttendee(Event event, ContentValues values) {
try { try {
Attendee attendee = new Attendee(new URI("mailto", values.getAsString(Attendees.ATTENDEE_EMAIL), null)); Attendee attendee = new Attendee(new URI("mailto", values.getAsString(Attendees.ATTENDEE_EMAIL), null));
ParameterList params = attendee.getParameters(); ParameterList params = attendee.getParameters();
@ -504,7 +492,7 @@ public class LocalCalendar extends LocalCollection<Event> {
} }
} }
void populateReminder(Event event, ContentValues row) throws RemoteException { void populateReminder(Event event, ContentValues row) {
VAlarm alarm = new VAlarm(new Dur(0, 0, -row.getAsInteger(Reminders.MINUTES), 0)); VAlarm alarm = new VAlarm(new Dur(0, 0, -row.getAsInteger(Reminders.MINUTES), 0));
PropertyList props = alarm.getProperties(); PropertyList props = alarm.getProperties();

View File

@ -11,6 +11,7 @@ import android.accounts.Account;
import android.content.ContentProviderClient; import android.content.ContentProviderClient;
import android.content.ContentProviderOperation; import android.content.ContentProviderOperation;
import android.content.ContentProviderOperation.Builder; import android.content.ContentProviderOperation.Builder;
import android.content.ContentProviderResult;
import android.content.ContentUris; import android.content.ContentUris;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.OperationApplicationException; import android.content.OperationApplicationException;
@ -21,14 +22,13 @@ import android.os.RemoteException;
import android.provider.CalendarContract; import android.provider.CalendarContract;
import android.util.Log; import android.util.Log;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import lombok.Cleanup; import lombok.Cleanup;
import lombok.Getter;
/** /**
* Represents a locally-stored synchronizable collection (for instance, the * Represents a locally-stored synchronizable collection (for instance, the
@ -40,9 +40,9 @@ import lombok.Getter;
public abstract class LocalCollection<T extends Resource> { public abstract class LocalCollection<T extends Resource> {
private static final String TAG = "davdroid.Collection"; private static final String TAG = "davdroid.Collection";
protected Account account; final protected Account account;
protected ContentProviderClient providerClient; final protected ContentProviderClient providerClient;
protected ArrayList<ContentProviderOperation> pendingOperations = new ArrayList<ContentProviderOperation>(); final protected ArrayList<ContentProviderOperation> pendingOperations = new ArrayList<>();
// database fields // database fields
@ -269,8 +269,8 @@ public abstract class LocalCollection<T extends Resource> {
* @return the new resource object */ * @return the new resource object */
abstract public T newResource(long localID, String resourceName, String eTag); abstract public T newResource(long localID, String resourceName, String eTag);
/** Enqueues adding the resource (including all data) to the local collection. Requires commit(). */ /** Enqueues adding the resource (including all data) to the local collection. */
public void add(Resource resource) { public void add(Resource resource) throws LocalStorageException {
int idx = pendingOperations.size(); int idx = pendingOperations.size();
pendingOperations.add( pendingOperations.add(
buildEntry(ContentProviderOperation.newInsert(entriesURI()), resource, false) buildEntry(ContentProviderOperation.newInsert(entriesURI()), resource, false)
@ -278,6 +278,7 @@ public abstract class LocalCollection<T extends Resource> {
.build()); .build());
addDataRows(resource, -1, idx); addDataRows(resource, -1, idx);
commit();
} }
/** Enqueues updating an existing resource in the local collection. The resource will be found by /** Enqueues updating an existing resource in the local collection. The resource will be found by
@ -292,6 +293,7 @@ public abstract class LocalCollection<T extends Resource> {
removeDataRows(localResource); removeDataRows(localResource);
addDataRows(remoteResource, localResource.getLocalID(), -1); addDataRows(remoteResource, localResource.getLocalID(), -1);
commit();
} }
/** Enqueues deleting a resource from the local collection. Requires commit(). */ /** Enqueues deleting a resource from the local collection. Requires commit(). */
@ -303,10 +305,11 @@ public abstract class LocalCollection<T extends Resource> {
} }
/** /**
* Enqueues deleting all resources except the give ones from the local collection. Requires commit(). * Deletes all resources except the give ones from the local collection.
* @param remoteResources resources with these remote file names will be kept * @param remoteResources resources with these remote file names will be kept
* @return number of deleted resources
*/ */
public void deleteAllExceptRemoteNames(Resource[] remoteResources) { public int deleteAllExceptRemoteNames(Resource[] remoteResources) throws LocalStorageException {
final String where; final String where;
if (remoteResources.length != 0) { if (remoteResources.length != 0) {
@ -319,12 +322,16 @@ public abstract class LocalCollection<T extends Resource> {
// delete all entries // delete all entries
where = entryColumnRemoteName() + " IS NOT NULL"; where = entryColumnRemoteName() + " IS NOT NULL";
ContentProviderOperation.Builder builder = ContentProviderOperation.newDelete(entriesURI()) try {
.withSelection( // restrict deletion to parent collection return providerClient.delete(
entriesURI(),
// restrict deletion to parent collection
entryColumnParentID() + "=? AND (" + where + ')', entryColumnParentID() + "=? AND (" + where + ')',
new String[] { String.valueOf(getId()) } new String[] { String.valueOf(getId()) }
); );
pendingOperations.add(builder.withYieldAllowed(true).build()); } catch (RemoteException e) {
throw new LocalStorageException("Couldn't delete local resources", e);
}
} }
@ -350,17 +357,21 @@ public abstract class LocalCollection<T extends Resource> {
} }
/** Commits enqueued operations to the content provider (for batch operations). */ /** Commits enqueued operations to the content provider (for batch operations). */
public void commit() throws LocalStorageException { public int commit() throws LocalStorageException {
int affected = 0;
if (!pendingOperations.isEmpty()) if (!pendingOperations.isEmpty())
try { try {
Log.d(TAG, "Committing " + pendingOperations.size() + " operations"); Log.d(TAG, "Committing " + pendingOperations.size() + " operations ...");
providerClient.applyBatch(pendingOperations); ContentProviderResult[] results = providerClient.applyBatch(pendingOperations);
for (ContentProviderResult result : results)
if (result != null && result.count != null)
affected += result.count;
Log.d(TAG, "... " + affected + " row(s) affected");
pendingOperations.clear(); pendingOperations.clear();
} catch (RemoteException ex) { } catch(OperationApplicationException | RemoteException ex) {
throw new LocalStorageException(ex);
} catch(OperationApplicationException ex) {
throw new LocalStorageException(ex); throw new LocalStorageException(ex);
} }
return affected;
} }

View File

@ -24,17 +24,15 @@ import net.fortuna.ical4j.model.Date;
import net.fortuna.ical4j.model.DateTime; import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.Dur; import net.fortuna.ical4j.model.Dur;
import net.fortuna.ical4j.model.TimeZone; import net.fortuna.ical4j.model.TimeZone;
import net.fortuna.ical4j.model.TimeZoneRegistry;
import net.fortuna.ical4j.model.property.Clazz; import net.fortuna.ical4j.model.property.Clazz;
import net.fortuna.ical4j.model.property.Completed; import net.fortuna.ical4j.model.property.Completed;
import net.fortuna.ical4j.model.property.Created;
import net.fortuna.ical4j.model.property.DtStart; import net.fortuna.ical4j.model.property.DtStart;
import net.fortuna.ical4j.model.property.Due; import net.fortuna.ical4j.model.property.Due;
import net.fortuna.ical4j.model.property.Duration; import net.fortuna.ical4j.model.property.Duration;
import net.fortuna.ical4j.model.property.Status; import net.fortuna.ical4j.model.property.Status;
import net.fortuna.ical4j.util.TimeZones; import net.fortuna.ical4j.util.TimeZones;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.dmfs.provider.tasks.TaskContract; import org.dmfs.provider.tasks.TaskContract;
import java.util.LinkedList; import java.util.LinkedList;
@ -52,7 +50,7 @@ public class LocalTaskList extends LocalCollection<Task> {
public static final String TASKS_AUTHORITY = "org.dmfs.tasks"; public static final String TASKS_AUTHORITY = "org.dmfs.tasks";
protected static String COLLECTION_COLUMN_CTAG = TaskContract.TaskLists.SYNC1; protected static final String COLLECTION_COLUMN_CTAG = TaskContract.TaskLists.SYNC1;
@Override protected Uri entriesURI() { return syncAdapterURI(TaskContract.Tasks.getContentUri(TASKS_AUTHORITY)); } @Override protected Uri entriesURI() { return syncAdapterURI(TaskContract.Tasks.getContentUri(TASKS_AUTHORITY)); }
@Override protected String entryColumnAccountType() { return TaskContract.Tasks.ACCOUNT_TYPE; } @Override protected String entryColumnAccountType() { return TaskContract.Tasks.ACCOUNT_TYPE; }
@ -67,7 +65,7 @@ public class LocalTaskList extends LocalCollection<Task> {
public static Uri create(Account account, ContentResolver resolver, ServerInfo.ResourceInfo info) throws LocalStorageException { public static Uri create(Account account, ContentResolver resolver, ServerInfo.ResourceInfo info) throws LocalStorageException {
final ContentProviderClient client = resolver.acquireContentProviderClient(TASKS_AUTHORITY); @Cleanup("release") final ContentProviderClient client = resolver.acquireContentProviderClient(TASKS_AUTHORITY);
if (client == null) if (client == null)
throw new LocalStorageException("No tasks provider found"); throw new LocalStorageException("No tasks provider found");
@ -101,7 +99,7 @@ public class LocalTaskList extends LocalCollection<Task> {
return taskList.toArray(new LocalTaskList[taskList.size()]); return taskList.toArray(new LocalTaskList[taskList.size()]);
} }
public LocalTaskList(Account account, ContentProviderClient providerClient, long id, String url) throws RemoteException { public LocalTaskList(Account account, ContentProviderClient providerClient, long id, String url) {
super(account, providerClient); super(account, providerClient);
this.id = id; this.id = id;
this.url = url; this.url = url;

View File

@ -17,10 +17,6 @@ public class RecordNotFoundException extends LocalStorageException {
private static final String detailMessage = "Record not found in local content provider"; private static final String detailMessage = "Record not found in local content provider";
RecordNotFoundException(Throwable ex) {
super(detailMessage, ex);
}
RecordNotFoundException() { RecordNotFoundException() {
super(detailMessage); super(detailMessage);
} }

View File

@ -7,11 +7,8 @@
*/ */
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 org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
@ -25,10 +22,7 @@ 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.DavCalendarQuery;
import at.bitfire.davdroid.webdav.DavException; import at.bitfire.davdroid.webdav.DavException;
import at.bitfire.davdroid.webdav.DavFilter;
import at.bitfire.davdroid.webdav.DavMultiget; import at.bitfire.davdroid.webdav.DavMultiget;
import at.bitfire.davdroid.webdav.DavNoContentException; import at.bitfire.davdroid.webdav.DavNoContentException;
import at.bitfire.davdroid.webdav.HttpException; import at.bitfire.davdroid.webdav.HttpException;
@ -38,7 +32,6 @@ import at.bitfire.davdroid.webdav.WebDavResource.PutMode;
import ezvcard.io.text.VCardParseException; import ezvcard.io.text.VCardParseException;
import lombok.Cleanup; import lombok.Cleanup;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
/** /**
* Represents a remotely stored synchronizable collection (collection as in * Represents a remotely stored synchronizable collection (collection as in
@ -49,7 +42,6 @@ import lombok.Setter;
public abstract class RemoteCollection<T extends Resource> { public abstract class RemoteCollection<T extends Resource> {
private static final String TAG = "davdroid.resource"; private static final String TAG = "davdroid.resource";
CloseableHttpClient httpClient;
URI baseURI; URI baseURI;
@Getter WebDavResource collection; @Getter WebDavResource collection;
@ -59,8 +51,6 @@ public abstract class RemoteCollection<T extends Resource> {
abstract protected T newResourceSkeleton(String name, String ETag); abstract protected T newResourceSkeleton(String name, String ETag);
public RemoteCollection(CloseableHttpClient httpClient, String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException { public RemoteCollection(CloseableHttpClient httpClient, String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException {
this.httpClient = httpClient;
baseURI = URIUtils.parseURI(baseURL, false); baseURI = URIUtils.parseURI(baseURL, false);
collection = new WebDavResource(httpClient, baseURI, user, password, preemptiveAuth); collection = new WebDavResource(httpClient, baseURI, user, password, preemptiveAuth);
} }
@ -101,12 +91,12 @@ public abstract class RemoteCollection<T extends Resource> {
else else
collection.propfind(HttpPropfind.Mode.MEMBERS_ETAG); collection.propfind(HttpPropfind.Mode.MEMBERS_ETAG);
List<T> resources = new LinkedList<T>(); List<T> resources = new LinkedList<>();
if (collection.getMembers() != null) if (collection.getMembers() != null)
for (WebDavResource member : collection.getMembers()) for (WebDavResource member : collection.getMembers())
resources.add(newResourceSkeleton(member.getName(), member.getETag())); resources.add(newResourceSkeleton(member.getName(), member.getETag()));
return resources.toArray(new Resource[0]); return resources.toArray(new Resource[resources.size()]);
} }
@ -115,16 +105,16 @@ public abstract class RemoteCollection<T extends Resource> {
public Resource[] multiGet(Resource[] resources) throws URISyntaxException, IOException, DavException, HttpException { public Resource[] multiGet(Resource[] resources) throws URISyntaxException, IOException, DavException, HttpException {
try { try {
if (resources.length == 1) if (resources.length == 1)
return (T[]) new Resource[] { get(resources[0]) }; return new Resource[] { get(resources[0]) };
Log.i(TAG, "Multi-getting " + resources.length + " remote resource(s)"); Log.i(TAG, "Multi-getting " + resources.length + " remote resource(s)");
LinkedList<String> names = new LinkedList<String>(); LinkedList<String> names = new LinkedList<>();
for (Resource resource : resources) for (Resource resource : resources)
names.add(resource.getName()); names.add(resource.getName());
LinkedList<T> foundResources = new LinkedList<T>(); LinkedList<T> foundResources = new LinkedList<>();
collection.multiGet(multiGetType(), names.toArray(new String[0])); collection.multiGet(multiGetType(), names.toArray(new String[names.size()]));
if (collection.getMembers() == null) if (collection.getMembers() == null)
throw new DavNoContentException(); throw new DavNoContentException();
@ -142,7 +132,7 @@ public abstract class RemoteCollection<T extends Resource> {
} }
} }
return foundResources.toArray(new Resource[0]); return foundResources.toArray(new Resource[foundResources.size()]);
} catch (InvalidResourceException e) { } catch (InvalidResourceException e) {
Log.e(TAG, "Couldn't parse entity from GET", e); Log.e(TAG, "Couldn't parse entity from GET", e);
} }
@ -172,7 +162,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 {
WebDavResource member = new WebDavResource(collection, res.getName(), res.getETag()); WebDavResource member = new WebDavResource(collection, res.getName(), res.getETag());
member.setContentType(res.getMimeType()); member.setContentType(res.getMimeType());
@ -193,7 +183,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 {
WebDavResource member = new WebDavResource(collection, res.getName(), res.getETag()); WebDavResource member = new WebDavResource(collection, res.getName(), res.getETag());
member.setContentType(res.getMimeType()); member.setContentType(res.getMimeType());

View File

@ -12,7 +12,6 @@ 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 at.bitfire.davdroid.webdav.DavException; import at.bitfire.davdroid.webdav.DavException;
import at.bitfire.davdroid.webdav.HttpException; import at.bitfire.davdroid.webdav.HttpException;
@ -58,6 +57,6 @@ public abstract class Resource {
public interface AssetDownloader { public interface AssetDownloader {
public byte[] download(URI url) throws URISyntaxException, IOException, HttpException, DavException; byte[] download(URI url) throws URISyntaxException, IOException, HttpException, DavException;
} }
} }

View File

@ -7,7 +7,6 @@
*/ */
package at.bitfire.davdroid.resource; package at.bitfire.davdroid.resource;
import java.io.Serializable;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.util.LinkedList; import java.util.LinkedList;
@ -20,10 +19,6 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor(suppressConstructorProperties=true) @RequiredArgsConstructor(suppressConstructorProperties=true)
@Data @Data
public class ServerInfo { public class ServerInfo {
enum Scheme {
HTTP, HTTPS, MAILTO
}
final private URI baseURI; final private URI baseURI;
final private String userName, password; final private String userName, password;
final boolean authPreemptive; final boolean authPreemptive;

View File

@ -38,7 +38,7 @@ public class AccountAuthenticatorService extends Service {
private static class AccountAuthenticator extends AbstractAccountAuthenticator { private static class AccountAuthenticator extends AbstractAccountAuthenticator {
Context context; final Context context;
public AccountAuthenticator(Context context) { public AccountAuthenticator(Context context) {
super(context); super(context);

View File

@ -19,7 +19,6 @@ import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.provider.CalendarContract; import android.provider.CalendarContract;
import android.provider.CalendarContract.Calendars; import android.provider.CalendarContract.Calendars;
import android.provider.ContactsContract;
import android.util.Log; import android.util.Log;
import java.net.URI; import java.net.URI;
@ -46,9 +45,9 @@ public class AccountSettings {
public final static long SYNC_INTERVAL_MANUALLY = -1; public final static long SYNC_INTERVAL_MANUALLY = -1;
Context context; final Context context;
AccountManager accountManager; final AccountManager accountManager;
Account account; final Account account;
public AccountSettings(Context context, Account account) { public AccountSettings(Context context, Account account) {
@ -78,7 +77,7 @@ public class AccountSettings {
if (addressBook.isEnabled()) { if (addressBook.isEnabled()) {
bundle.putString(KEY_ADDRESSBOOK_URL, addressBook.getURL()); bundle.putString(KEY_ADDRESSBOOK_URL, addressBook.getURL());
bundle.putString(KEY_ADDRESSBOOK_VCARD_VERSION, addressBook.getVCardVersion().getVersion()); bundle.putString(KEY_ADDRESSBOOK_VCARD_VERSION, addressBook.getVCardVersion().getVersion());
continue; break;
} }
return bundle; return bundle;
} }

View File

@ -61,7 +61,7 @@ public class CalendarsSyncAdapterService extends Service {
boolean preemptive = settings.getPreemptiveAuth(); boolean preemptive = settings.getPreemptiveAuth();
try { try {
Map<LocalCollection<?>, RemoteCollection<?>> map = new HashMap<LocalCollection<?>, RemoteCollection<?>>(); Map<LocalCollection<?>, RemoteCollection<?>> map = new HashMap<>();
for (LocalCalendar calendar : LocalCalendar.findAll(account, provider)) { for (LocalCalendar calendar : LocalCalendar.findAll(account, provider)) {
RemoteCollection<?> dav = new CalDavCalendar(httpClient, calendar.getUrl(), userName, password, preemptive); RemoteCollection<?> dav = new CalDavCalendar(httpClient, calendar.getUrl(), userName, password, preemptive);

View File

@ -67,7 +67,7 @@ public class ContactsSyncAdapterService extends Service {
LocalCollection<?> database = new LocalAddressBook(account, provider, settings); LocalCollection<?> database = new LocalAddressBook(account, provider, settings);
RemoteCollection<?> dav = new CardDavAddressBook(settings, 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<>();
map.put(database, dav); map.put(database, dav);
return map; return map;

View File

@ -8,8 +8,6 @@
package at.bitfire.davdroid.syncadapter; package at.bitfire.davdroid.syncadapter;
import android.accounts.Account; import android.accounts.Account;
import android.accounts.AccountManager;
import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
@ -19,17 +17,15 @@ import android.content.ContentProviderClient;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SyncResult; import android.content.SyncResult;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.Settings; import android.provider.Settings;
import android.util.Log; import android.util.Log;
import org.apache.commons.lang.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
@ -57,7 +53,7 @@ public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter impleme
@Getter private static String androidID; @Getter private static String androidID;
protected Context context; final protected Context context;
/* We use one static httpClient for /* We use one static httpClient for
* - all sync adapters (CalendarsSyncAdapter, ContactsSyncAdapter) * - all sync adapters (CalendarsSyncAdapter, ContactsSyncAdapter)
@ -120,7 +116,6 @@ public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter impleme
httpClientLock.writeLock().lock(); httpClientLock.writeLock().lock();
if (httpClient == null) { if (httpClient == null) {
Log.d(TAG, "Creating new DavHttpClient"); Log.d(TAG, "Creating new DavHttpClient");
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getContext());
httpClient = DavHttpClient.create(); httpClient = DavHttpClient.create();
} }
@ -129,10 +124,6 @@ public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter impleme
httpClientLock.readLock().lock(); httpClientLock.readLock().lock();
httpClientLock.writeLock().unlock(); httpClientLock.writeLock().unlock();
// TODO use VCard 4.0 if possible
AccountSettings accountSettings = new AccountSettings(getContext(), account);
Log.d(TAG, "Server supports VCard version " + accountSettings.getAddressBookVCardVersion());
Exception exceptionToShow = null; // exception to show notification for Exception exceptionToShow = null; // exception to show notification for
Intent exceptionIntent = null; // what shall happen when clicking on the exception notification Intent exceptionIntent = null; // what shall happen when clicking on the exception notification
try { try {
@ -199,7 +190,7 @@ public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter impleme
.setContentTitle(context.getString(R.string.sync_error_title)) .setContentTitle(context.getString(R.string.sync_error_title))
.setContentText(exceptionToShow.getLocalizedMessage()) .setContentText(exceptionToShow.getLocalizedMessage())
.setContentInfo(account.name) .setContentInfo(account.name)
.setStyle(new Notification.BigTextStyle().bigText(account.name + ":\n" + ExceptionUtils.getFullStackTrace(exceptionToShow))) .setStyle(new Notification.BigTextStyle().bigText(account.name + ":\n" + ExceptionUtils.getStackTrace(exceptionToShow)))
.setContentIntent(contentIntent); .setContentIntent(contentIntent);
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);

View File

@ -10,8 +10,6 @@ package at.bitfire.davdroid.syncadapter;
import android.content.SyncResult; import android.content.SyncResult;
import android.util.Log; import android.util.Log;
import net.fortuna.ical4j.model.ValidationException;
import java.io.IOException; import java.io.IOException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.HashSet; import java.util.HashSet;
@ -33,8 +31,8 @@ public class SyncManager {
private static final int MAX_MULTIGET_RESOURCES = 35; private static final int MAX_MULTIGET_RESOURCES = 35;
protected LocalCollection<? extends Resource> local; final protected LocalCollection<? extends Resource> local;
protected RemoteCollection<? extends Resource> remote; final protected RemoteCollection<? extends Resource> remote;
public SyncManager(LocalCollection<? extends Resource> local, RemoteCollection<? extends Resource> remote) { public SyncManager(LocalCollection<? extends Resource> local, RemoteCollection<? extends Resource> remote) {
@ -49,10 +47,8 @@ public class SyncManager {
addedRemotely = pushNew(), addedRemotely = pushNew(),
updatedRemotely = pushDirty(); updatedRemotely = pushDirty();
syncResult.stats.numEntries = deletedRemotely + addedRemotely + updatedRemotely;
// PHASE 2A: check if there's a reason to do a sync with remote (= forced sync or remote CTag changed) // PHASE 2A: check if there's a reason to do a sync with remote (= forced sync or remote CTag changed)
boolean fetchCollection = syncResult.stats.numEntries > 0; boolean fetchCollection = (deletedRemotely + addedRemotely + updatedRemotely) > 0;
if (manualSync) { if (manualSync) {
Log.i(TAG, "Synchronization forced"); Log.i(TAG, "Synchronization forced");
fetchCollection = true; fetchCollection = true;
@ -72,8 +68,8 @@ public class SyncManager {
// PHASE 2B: detect details of remote changes // PHASE 2B: detect details of remote changes
Log.i(TAG, "Fetching remote resource list"); Log.i(TAG, "Fetching remote resource list");
Set<Resource> remotelyAdded = new HashSet<Resource>(), Set<Resource> remotelyAdded = new HashSet<>(),
remotelyUpdated = new HashSet<Resource>(); remotelyUpdated = new HashSet<>();
Resource[] remoteResources = remote.getMemberETags(); Resource[] remoteResources = remote.getMemberETags();
for (Resource remoteResource : remoteResources) { for (Resource remoteResource : remoteResources) {
@ -87,13 +83,13 @@ public class SyncManager {
} }
// PHASE 3: pull remote changes from server // PHASE 3: pull remote changes from server
syncResult.stats.numInserts = pullNew(remotelyAdded.toArray(new Resource[0])); syncResult.stats.numInserts = pullNew(remotelyAdded.toArray(new Resource[remotelyAdded.size()]));
syncResult.stats.numUpdates = pullChanged(remotelyUpdated.toArray(new Resource[0])); syncResult.stats.numUpdates = pullChanged(remotelyUpdated.toArray(new Resource[remotelyUpdated.size()]));
syncResult.stats.numEntries += syncResult.stats.numInserts + syncResult.stats.numUpdates;
Log.i(TAG, "Removing non-dirty resources that are not present remotely anymore"); Log.i(TAG, "Removing non-dirty resources that are not present remotely anymore");
local.deleteAllExceptRemoteNames(remoteResources); syncResult.stats.numDeletes = local.deleteAllExceptRemoteNames(remoteResources);
local.commit();
syncResult.stats.numEntries = syncResult.stats.numInserts + syncResult.stats.numUpdates + syncResult.stats.numDeletes;
// update collection CTag // update collection CTag
Log.i(TAG, "Sync complete, fetching new CTag"); Log.i(TAG, "Sync complete, fetching new CTag");
@ -145,10 +141,8 @@ public class SyncManager {
local.updateETag(res, eTag); local.updateETag(res, eTag);
local.clearDirty(res); local.clearDirty(res);
count++; count++;
} catch(PreconditionFailedException e) { } catch (PreconditionFailedException e) {
Log.i(TAG, "Didn't overwrite existing resource with other content"); Log.i(TAG, "Didn't overwrite existing resource with other content");
} catch (ValidationException e) {
Log.e(TAG, "Couldn't create entity for adding: " + e.toString());
} catch (RecordNotFoundException e) { } catch (RecordNotFoundException e) {
Log.wtf(TAG, "Couldn't read new record", e); Log.wtf(TAG, "Couldn't read new record", e);
} }
@ -171,10 +165,8 @@ public class SyncManager {
local.updateETag(res, eTag); local.updateETag(res, eTag);
local.clearDirty(res); local.clearDirty(res);
count++; count++;
} catch(PreconditionFailedException e) { } catch (PreconditionFailedException e) {
Log.i(TAG, "Locally changed resource has been changed on the server in the meanwhile"); Log.i(TAG, "Locally changed resource has been changed on the server in the meanwhile");
} catch (ValidationException e) {
Log.e(TAG, "Couldn't create entity for updating: " + e.toString());
} catch (RecordNotFoundException e) { } catch (RecordNotFoundException e) {
Log.e(TAG, "Couldn't read dirty record", e); Log.e(TAG, "Couldn't read dirty record", e);
} }
@ -193,7 +185,6 @@ public class SyncManager {
for (Resource res : remote.multiGet(resources)) { for (Resource res : remote.multiGet(resources)) {
Log.d(TAG, "Adding " + res.getName()); Log.d(TAG, "Adding " + res.getName());
local.add(res); local.add(res);
local.commit();
count++; count++;
} }
return count; return count;
@ -207,7 +198,6 @@ public class SyncManager {
for (Resource res : remote.multiGet(resources)) { for (Resource res : remote.multiGet(resources)) {
Log.i(TAG, "Updating " + res.getName()); Log.i(TAG, "Updating " + res.getName());
local.updateByRemoteName(res); local.updateByRemoteName(res);
local.commit();
count++; count++;
} }
return count; return count;

View File

@ -61,7 +61,7 @@ public class TasksSyncAdapterService extends Service {
boolean preemptive = settings.getPreemptiveAuth(); boolean preemptive = settings.getPreemptiveAuth();
try { try {
Map<LocalCollection<?>, RemoteCollection<?>> map = new HashMap<LocalCollection<?>, RemoteCollection<?>>(); Map<LocalCollection<?>, RemoteCollection<?>> map = new HashMap<>();
for (LocalTaskList calendar : LocalTaskList.findAll(account, provider)) { for (LocalTaskList calendar : LocalTaskList.findAll(account, provider)) {
RemoteCollection<?> dav = new CalDavTaskList(httpClient, calendar.getUrl(), userName, password, preemptive); RemoteCollection<?> dav = new CalDavTaskList(httpClient, calendar.getUrl(), userName, password, preemptive);

View File

@ -22,8 +22,8 @@ import android.widget.TextView;
import at.bitfire.davdroid.Constants; import at.bitfire.davdroid.Constants;
import at.bitfire.davdroid.R; import at.bitfire.davdroid.R;
import at.bitfire.davdroid.ui.setup.AddAccountActivity;
import at.bitfire.davdroid.ui.settings.SettingsActivity; import at.bitfire.davdroid.ui.settings.SettingsActivity;
import at.bitfire.davdroid.ui.setup.AddAccountActivity;
public class MainActivity extends Activity { public class MainActivity extends Activity {

View File

@ -12,7 +12,6 @@ import android.accounts.Account;
import android.app.Activity; import android.app.Activity;
import android.app.FragmentManager; import android.app.FragmentManager;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log;
import at.bitfire.davdroid.R; import at.bitfire.davdroid.R;

View File

@ -9,7 +9,6 @@
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;
@ -20,13 +19,10 @@ import android.preference.SwitchPreference;
import android.provider.CalendarContract; import android.provider.CalendarContract;
import android.provider.ContactsContract; import android.provider.ContactsContract;
import org.dmfs.provider.tasks.TaskContract;
import at.bitfire.davdroid.R; import at.bitfire.davdroid.R;
import at.bitfire.davdroid.resource.LocalTaskList; import at.bitfire.davdroid.resource.LocalTaskList;
import at.bitfire.davdroid.syncadapter.AccountSettings; import at.bitfire.davdroid.syncadapter.AccountSettings;
import ezvcard.VCardVersion; import ezvcard.VCardVersion;
import lombok.Setter;
public class AccountFragment extends PreferenceFragment { public class AccountFragment extends PreferenceFragment {
final static String ARG_ACCOUNT = "account"; final static String ARG_ACCOUNT = "account";

View File

@ -11,10 +11,8 @@ package at.bitfire.davdroid.ui.settings;
import android.accounts.Account; import android.accounts.Account;
import android.app.Activity; import android.app.Activity;
import android.app.FragmentTransaction; import android.app.FragmentTransaction;
import android.app.ListFragment;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.widget.ListView;
import at.bitfire.davdroid.R; import at.bitfire.davdroid.R;

View File

@ -32,7 +32,7 @@ public class SettingsScopeFragment extends ListFragment {
final String[] accountNames = new String[accounts.length]; final String[] accountNames = new String[accounts.length];
for (int i = 0; i < accounts.length; i++) for (int i = 0; i < accounts.length; i++)
accountNames[i] = accounts[i].name; accountNames[i] = accounts[i].name;
setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_activated_1, accountNames)); setListAdapter(new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_activated_1, accountNames));
return super.onCreateView(inflater, container, savedInstanceState); return super.onCreateView(inflater, container, savedInstanceState);
} }

View File

@ -142,8 +142,7 @@ public class AccountDetailsFragment extends Fragment implements TextWatcher {
@Override @Override
public void onPrepareOptionsMenu(Menu menu) { public void onPrepareOptionsMenu(Menu menu) {
boolean ok = false; boolean ok = editAccountName.getText().length() > 0;
ok = editAccountName.getText().length() > 0;
MenuItem item = menu.findItem(R.id.add_account); MenuItem item = menu.findItem(R.id.add_account);
item.setEnabled(ok); item.setEnabled(ok);
} }

View File

@ -14,7 +14,6 @@ import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View;
import at.bitfire.davdroid.Constants; import at.bitfire.davdroid.Constants;
import at.bitfire.davdroid.R; import at.bitfire.davdroid.R;
@ -45,11 +44,6 @@ public class AddAccountActivity extends Activity {
return true; return true;
} }
public void installTasksApp(View view) {
final Intent intent = new Intent(Intent.ACTION_VIEW).setData(Uri.parse("market://details?id=org.dmfs.tasks"));
startActivity(intent);
}
public void showHelp(MenuItem item) { public void showHelp(MenuItem item) {
startActivityForResult(new Intent(Intent.ACTION_VIEW, Uri.parse(Constants.WEB_URL_HELP)), 0); startActivityForResult(new Intent(Intent.ACTION_VIEW, Uri.parse(Constants.WEB_URL_HELP)), 0);
} }

View File

@ -8,20 +8,11 @@
package at.bitfire.davdroid.ui.setup; package at.bitfire.davdroid.ui.setup;
import android.app.DialogFragment;
import android.app.Fragment; import android.app.Fragment;
import android.app.FragmentManager; import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.text.Html; import android.text.Html;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@ -30,13 +21,9 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import at.bitfire.davdroid.Constants;
import at.bitfire.davdroid.R; import at.bitfire.davdroid.R;
import at.bitfire.davdroid.resource.LocalTaskList;
public class InstallAppsFragment extends Fragment { public class InstallAppsFragment extends Fragment {
private static final String TAG = "davdroid.setup";
// https://code.google.com/p/android/issues/detail?id=25906 // https://code.google.com/p/android/issues/detail?id=25906
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@ -68,8 +55,6 @@ public class InstallAppsFragment extends Fragment {
} }
protected void skip() { protected void skip() {
FragmentManager fm = getFragmentManager();
getFragmentManager().beginTransaction() getFragmentManager().beginTransaction()
.replace(R.id.right_pane, new SelectCollectionsFragment()) .replace(R.id.right_pane, new SelectCollectionsFragment())
.addToBackStack(null) .addToBackStack(null)

View File

@ -21,7 +21,7 @@ import at.bitfire.davdroid.R;
public class LoginTypeFragment extends Fragment { public class LoginTypeFragment extends Fragment {
protected RadioButton btnTypeEmail, btnTypeURL; protected RadioButton btnTypeEmail;
@Override @Override
@ -29,7 +29,6 @@ public class LoginTypeFragment extends Fragment {
View v = inflater.inflate(R.layout.setup_login_type, container, false); View v = inflater.inflate(R.layout.setup_login_type, container, false);
btnTypeEmail = (RadioButton)v.findViewById(R.id.login_type_email); btnTypeEmail = (RadioButton)v.findViewById(R.id.login_type_email);
btnTypeURL = (RadioButton)v.findViewById(R.id.login_type_url);
setHasOptionsMenu(true); setHasOptionsMenu(true);

View File

@ -21,13 +21,12 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener; import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Button;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.EditText; import android.widget.EditText;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
@ -40,7 +39,6 @@ public class LoginURLFragment extends Fragment implements TextWatcher {
protected TextView textHttpWarning; protected TextView textHttpWarning;
protected EditText editBaseURI, editUserName, editPassword; protected EditText editBaseURI, editUserName, editPassword;
protected CheckBox checkboxPreemptive; protected CheckBox checkboxPreemptive;
protected Button btnNext;
@Override @Override

View File

@ -18,10 +18,9 @@ import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.Toast; import android.widget.Toast;
import org.apache.commons.lang.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.HttpException; import org.apache.http.HttpException;
import java.io.IOException; import java.io.IOException;
@ -44,8 +43,6 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC
EXTRA_PASSWORD = "password", EXTRA_PASSWORD = "password",
EXTRA_AUTH_PREEMPTIVE = "auth_preemptive"; EXTRA_AUTH_PREEMPTIVE = "auth_preemptive";
ProgressBar progressBar;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);

View File

@ -44,8 +44,8 @@ public class SelectCollectionsAdapter extends BaseAdapter implements ListAdapter
TYPE_TASK_LISTS_HEADING = 4, TYPE_TASK_LISTS_HEADING = 4,
TYPE_TASK_LISTS_ROW = 5; TYPE_TASK_LISTS_ROW = 5;
protected Context context; final protected Context context;
protected ServerInfo serverInfo; final protected ServerInfo serverInfo;
@Getter protected int @Getter protected int
nAddressBooks, nAddressBookHeadings, nAddressBooks, nAddressBookHeadings,
nCalendars, nCalendarHeadings, nCalendars, nCalendarHeadings,
@ -160,7 +160,6 @@ public class SelectCollectionsAdapter extends BaseAdapter implements ListAdapter
} }
// step 2: fill view with content // step 2: fill view with content
int collectionIcon;
switch (viewType) { switch (viewType) {
case TYPE_ADDRESS_BOOKS_ROW: case TYPE_ADDRESS_BOOKS_ROW:
setContent((CheckedTextView)v, R.drawable.addressbook, (ServerInfo.ResourceInfo)getItem(position)); setContent((CheckedTextView)v, R.drawable.addressbook, (ServerInfo.ResourceInfo)getItem(position));

View File

@ -1,63 +0,0 @@
/*
* Copyright © 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.ui.setup;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.List;
import at.bitfire.davdroid.webdav.WebDavResource;
public class WebDavResourceAdapter extends BaseAdapter {
protected int viewId;
protected LayoutInflater inflater;
WebDavResource[] items;
public WebDavResourceAdapter(Context context, int textViewResourceId, List<WebDavResource> objects) {
viewId = textViewResourceId;
inflater = LayoutInflater.from(context);
items = objects.toArray(new WebDavResource[0]);
}
@Override
public View getView(int position, View view, ViewGroup parent) {
WebDavResource item = items[position];
View itemView = (View)inflater.inflate(viewId, null);
TextView textName = (TextView) itemView.findViewById(android.R.id.text1);
textName.setText(item.getDisplayName());
TextView textDescription = (TextView) itemView.findViewById(android.R.id.text2);
String description = item.getDescription();
if (description == null)
description = item.getLocation().getPath();
textDescription.setText(description);
return itemView;
}
@Override
public int getCount() {
return items.length;
}
@Override
public Object getItem(int position) {
return items[position];
}
@Override
public long getItemId(int position) {
return position;
}
}

View File

@ -11,7 +11,6 @@ package at.bitfire.davdroid.webdav;
import org.simpleframework.xml.Attribute; import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Element; import org.simpleframework.xml.Element;
import org.simpleframework.xml.Namespace; import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.Root;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@ -23,7 +22,7 @@ public class DavCompFilter {
} }
@Attribute(required=false) @Attribute(required=false)
String name; final String name;
@Element(required=false,name="comp-filter") @Element(required=false,name="comp-filter")
@Getter @Setter DavCompFilter compFilter; @Getter @Setter DavCompFilter compFilter;

View File

@ -7,7 +7,7 @@
*/ */
package at.bitfire.davdroid.webdav; package at.bitfire.davdroid.webdav;
import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import org.apache.http.HttpRequest; import org.apache.http.HttpRequest;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandlerHC4; import org.apache.http.impl.client.DefaultHttpRequestRetryHandlerHC4;

View File

@ -49,7 +49,7 @@ public class DavMultiget {
multiget.prop.calendarData = new DavProp.CalendarData(); multiget.prop.calendarData = new DavProp.CalendarData();
} }
multiget.hrefs = new ArrayList<DavHref>(names.length); multiget.hrefs = new ArrayList<>(names.length);
for (String name : names) for (String name : names)
multiget.hrefs.add(new DavHref(name)); multiget.hrefs.add(new DavHref(name));

View File

@ -13,8 +13,6 @@ import org.simpleframework.xml.Root;
import java.util.List; import java.util.List;
import lombok.Getter;
@Root(strict=false) @Root(strict=false)
public class DavResponse { public class DavResponse {
@Element @Element

View File

@ -56,19 +56,19 @@ public class HttpPropfind extends HttpEntityEnclosingRequestBaseHC4 {
depth = 1; depth = 1;
propfind.prop.displayname = new DavProp.DisplayName(); propfind.prop.displayname = new DavProp.DisplayName();
propfind.prop.resourcetype = new DavProp.ResourceType(); propfind.prop.resourcetype = new DavProp.ResourceType();
propfind.prop.currentUserPrivilegeSet = new LinkedList<DavProp.Privilege>(); propfind.prop.currentUserPrivilegeSet = new LinkedList<>();
propfind.prop.addressbookDescription = new DavProp.AddressbookDescription(); propfind.prop.addressbookDescription = new DavProp.AddressbookDescription();
propfind.prop.supportedAddressData = new LinkedList<DavProp.AddressDataType>(); propfind.prop.supportedAddressData = new LinkedList<>();
break; break;
case CALDAV_COLLECTIONS: case CALDAV_COLLECTIONS:
depth = 1; depth = 1;
propfind.prop.displayname = new DavProp.DisplayName(); propfind.prop.displayname = new DavProp.DisplayName();
propfind.prop.resourcetype = new DavProp.ResourceType(); propfind.prop.resourcetype = new DavProp.ResourceType();
propfind.prop.currentUserPrivilegeSet = new LinkedList<DavProp.Privilege>(); propfind.prop.currentUserPrivilegeSet = new LinkedList<>();
propfind.prop.calendarDescription = new DavProp.CalendarDescription(); propfind.prop.calendarDescription = new DavProp.CalendarDescription();
propfind.prop.calendarColor = new DavProp.CalendarColor(); propfind.prop.calendarColor = new DavProp.CalendarColor();
propfind.prop.calendarTimezone = new DavProp.CalendarTimezone(); propfind.prop.calendarTimezone = new DavProp.CalendarTimezone();
propfind.prop.supportedCalendarComponentSet = new LinkedList<DavProp.Comp>(); propfind.prop.supportedCalendarComponentSet = new LinkedList<>();
break; break;
case COLLECTION_CTAG: case COLLECTION_CTAG:
propfind.prop.getctag = new DavProp.GetCTag(); propfind.prop.getctag = new DavProp.GetCTag();

View File

@ -11,7 +11,7 @@ package at.bitfire.davdroid.webdav;
import android.os.Build; import android.os.Build;
import android.util.Log; import android.util.Log;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.conn.ssl.BrowserCompatHostnameVerifierHC4; import org.apache.http.conn.ssl.BrowserCompatHostnameVerifierHC4;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier; import org.apache.http.conn.ssl.X509HostnameVerifier;
@ -28,7 +28,7 @@ import javax.net.ssl.SSLSocketFactory;
import lombok.Cleanup; import lombok.Cleanup;
public class TlsSniSocketFactory extends SSLConnectionSocketFactory { public class TlsSniSocketFactory extends SSLConnectionSocketFactory {
private static final String TAG = "davdroid.TlsSniSocketFactory"; private static final String TAG = "davdroid.TLS_SNI";
public static TlsSniSocketFactory getSocketFactory() { public static TlsSniSocketFactory getSocketFactory() {
return new TlsSniSocketFactory( return new TlsSniSocketFactory(
@ -48,18 +48,17 @@ public class TlsSniSocketFactory extends SSLConnectionSocketFactory {
/* set reasonable protocol versions */ /* set reasonable protocol versions */
// - enable all supported protocols (enables TLSv1.1 and TLSv1.2 on Android <5.0) // - enable all supported protocols (enables TLSv1.1 and TLSv1.2 on Android <5.0)
// - remove all SSL versions (especially SSLv3) because they're insecure now // - remove all SSL versions (especially SSLv3) because they're insecure now
List<String> protocols = new LinkedList<String>(); List<String> protocols = new LinkedList<>();
for (String protocol : socket.getSupportedProtocols()) for (String protocol : socket.getSupportedProtocols())
if (!protocol.toUpperCase().contains("SSL")) if (!protocol.toUpperCase().contains("SSL"))
protocols.add(protocol); protocols.add(protocol);
Log.v(TAG, "Setting allowed TLS protocols: " + StringUtils.join(protocols, ", ")); Log.v(TAG, "Setting allowed TLS protocols: " + StringUtils.join(protocols, ", "));
TlsSniSocketFactory.protocols = protocols.toArray(new String[0]); TlsSniSocketFactory.protocols = protocols.toArray(new String[protocols.size()]);
/* set reasonable cipher suites */ /* set reasonable cipher suites */
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
// choose secure cipher suites // choose secure cipher suites
List<String> allowedCiphers = Arrays.asList(new String[]{ List<String> allowedCiphers = Arrays.asList(
// allowed secure ciphers according to NIST.SP.800-52r1.pdf Section 3.3.1 (see docs directory)
// TLS 1.2 // TLS 1.2
"TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_256_GCM_SHA384",
"TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_128_GCM_SHA256",
@ -76,13 +75,12 @@ public class TlsSniSocketFactory extends SSLConnectionSocketFactory {
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");
});
List<String> availableCiphers = Arrays.asList(socket.getSupportedCipherSuites()); List<String> availableCiphers = Arrays.asList(socket.getSupportedCipherSuites());
// preferred ciphers = allowed Ciphers \ availableCiphers // preferred ciphers = allowed Ciphers \ availableCiphers
HashSet<String> preferredCiphers = new HashSet<String>(allowedCiphers); HashSet<String> preferredCiphers = new HashSet<>(allowedCiphers);
preferredCiphers.retainAll(availableCiphers); preferredCiphers.retainAll(availableCiphers);
// add preferred ciphers to enabled ciphers // add preferred ciphers to enabled ciphers
@ -90,10 +88,10 @@ public class TlsSniSocketFactory extends SSLConnectionSocketFactory {
// but I guess for the security level of DAVdroid, disabling of insecure // but I guess for the security level of DAVdroid, disabling of insecure
// ciphers should be a server-side task // ciphers should be a server-side task
HashSet<String> enabledCiphers = preferredCiphers; HashSet<String> enabledCiphers = preferredCiphers;
enabledCiphers.addAll(new HashSet<String>(Arrays.asList(socket.getEnabledCipherSuites()))); enabledCiphers.addAll(new HashSet<>(Arrays.asList(socket.getEnabledCipherSuites())));
Log.v(TAG, "Setting allowed TLS ciphers: " + StringUtils.join(enabledCiphers, ", ")); Log.v(TAG, "Setting allowed TLS ciphers: " + StringUtils.join(enabledCiphers, ", "));
TlsSniSocketFactory.cipherSuites = enabledCiphers.toArray(new String[0]); TlsSniSocketFactory.cipherSuites = enabledCiphers.toArray(new String[enabledCiphers.size()]);
} }
} catch (IOException e) { } catch (IOException e) {
} }

View File

@ -9,7 +9,7 @@ package at.bitfire.davdroid.webdav;
import android.util.Log; import android.util.Log;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header; import org.apache.http.Header;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.HttpHost; import org.apache.http.HttpHost;
@ -25,7 +25,6 @@ import org.apache.http.client.methods.HttpGetHC4;
import org.apache.http.client.methods.HttpOptionsHC4; import org.apache.http.client.methods.HttpOptionsHC4;
import org.apache.http.client.methods.HttpPutHC4; import org.apache.http.client.methods.HttpPutHC4;
import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIUtilsHC4;
import org.apache.http.entity.ByteArrayEntityHC4; import org.apache.http.entity.ByteArrayEntityHC4;
import org.apache.http.impl.auth.BasicSchemeHC4; import org.apache.http.impl.auth.BasicSchemeHC4;
import org.apache.http.impl.client.BasicAuthCache; import org.apache.http.impl.client.BasicAuthCache;
@ -83,11 +82,11 @@ public class WebDavResource {
@Getter protected URI location; @Getter protected URI location;
// DAV capabilities (DAV: header) and allowed DAV methods (set for OPTIONS request) // DAV capabilities (DAV: header) and allowed DAV methods (set for OPTIONS request)
protected Set<String> capabilities = new HashSet<String>(), protected Set<String> capabilities = new HashSet<>(),
methods = new HashSet<String>(); methods = new HashSet<>();
// DAV properties // DAV properties
protected HashMap<Property, String> properties = new HashMap<Property, String>(); protected HashMap<Property, String> properties = new HashMap<>();
@Getter protected List<String> supportedComponents; @Getter protected List<String> supportedComponents;
// list of members (only for collections) // list of members (only for collections)
@ -294,13 +293,13 @@ public class WebDavResource {
// so we have to handle redirections manually and create a new request for the new location // so we have to handle redirections manually and create a new request for the new location
for (int i = context.getRequestConfig().getMaxRedirects(); i > 0; i--) { for (int i = context.getRequestConfig().getMaxRedirects(); i > 0; i--) {
// build multi-get XML request // build multi-get XML request
List<String> hrefs = new LinkedList<String>(); List<String> hrefs = new LinkedList<>();
for (String name : names) for (String name : names)
// name may contain "%" which have to be encoded use non-quoting URI constructor and getRawPath() // name may contain "%" which have to be encoded use non-quoting URI constructor and getRawPath()
// name may also contain ":", so prepend "./" because even the non-quoting URI constructor parses after constructing // name may also contain ":", so prepend "./" because even the non-quoting URI constructor parses after constructing
// DAVdroid ensures that collections always have a trailing slash, so "./" won't go down in directory hierarchy // DAVdroid ensures that collections always have a trailing slash, so "./" won't go down in directory hierarchy
hrefs.add(location.resolve(new URI(null, null, "./" + name, null)).getRawPath()); hrefs.add(location.resolve(new URI(null, null, "./" + name, null)).getRawPath());
DavMultiget multiget = DavMultiget.newRequest(type, hrefs.toArray(new String[0])); DavMultiget multiget = DavMultiget.newRequest(type, hrefs.toArray(new String[hrefs.size()]));
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
try { try {
@ -456,7 +455,7 @@ public class WebDavResource {
return; return;
// member list will be built from response // member list will be built from response
List<WebDavResource> members = new LinkedList<WebDavResource>(); List<WebDavResource> members = new LinkedList<>();
// iterate through all resources (either ourselves or member) // iterate through all resources (either ourselves or member)
for (DavResponse singleResponse : multiStatus.response) { for (DavResponse singleResponse : multiStatus.response) {
@ -470,7 +469,7 @@ public class WebDavResource {
Log.d(TAG, "Processing multi-status element: " + href); Log.d(TAG, "Processing multi-status element: " + href);
// process known properties // process known properties
HashMap<Property, String> properties = new HashMap<Property, String>(); HashMap<Property, String> properties = new HashMap<>();
List<String> supportedComponents = null; List<String> supportedComponents = null;
byte[] data = null; byte[] data = null;
@ -551,7 +550,7 @@ public class WebDavResource {
} }
if (prop.supportedCalendarComponentSet != null) { if (prop.supportedCalendarComponentSet != null) {
supportedComponents = new LinkedList<String>(); supportedComponents = new LinkedList<>();
for (Comp component : prop.supportedCalendarComponentSet) for (Comp component : prop.supportedCalendarComponentSet)
supportedComponents.add(component.getName()); supportedComponents.add(component.getName());
} }