mirror of
https://github.com/etesync/android
synced 2024-11-22 16:08:13 +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:
parent
c8cfbd6b07
commit
a796a1e9b3
@ -32,6 +32,7 @@ android {
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
exclude 'LICENSE'
|
||||
exclude 'META-INF/LICENSE.txt'
|
||||
exclude 'META-INF/NOTICE.txt'
|
||||
}
|
||||
@ -43,12 +44,15 @@ configurations.all {
|
||||
|
||||
dependencies {
|
||||
// Apache Commons
|
||||
compile 'commons-lang:commons-lang:2.6'
|
||||
compile 'org.apache.commons:commons-lang3:3.4'
|
||||
compile 'commons-io:commons-io:2.4'
|
||||
// Lombok for useful @helpers
|
||||
provided 'org.projectlombok:lombok:1.16.4'
|
||||
// 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
|
||||
compile('com.googlecode.ez-vcard:ez-vcard:0.9.6') {
|
||||
// hCard functionality not needed
|
||||
|
@ -73,22 +73,22 @@ public class ContactTest extends InstrumentationTestCase {
|
||||
assertTrue(Arrays.equals(c.getPhoto(), expectedPhoto));
|
||||
}
|
||||
|
||||
public void testParseInvalidUnknownProperties() throws IOException, InvalidResourceException {
|
||||
public void testParseInvalidUnknownProperties() throws IOException {
|
||||
Contact c = parseVCF("invalid-unknown-properties.vcf");
|
||||
assertEquals("VCard with invalid unknown properties", c.getDisplayName());
|
||||
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);
|
||||
Contact c = new Contact(fname, null);
|
||||
c.parseEntity(in, new Resource.AssetDownloader() {
|
||||
@Override
|
||||
public byte[] download(URI uri) throws URISyntaxException, IOException, HttpException, DavException {
|
||||
return IOUtils.toByteArray(uri);
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public byte[] download(URI uri) throws URISyntaxException, IOException, HttpException, DavException {
|
||||
return IOUtils.toByteArray(uri);
|
||||
}
|
||||
});
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ public class LocalCalendarTest extends InstrumentationTestCase {
|
||||
Context targetContext;
|
||||
|
||||
ContentProviderClient providerClient;
|
||||
Account testAccount = new Account(calendarName, accountType);
|
||||
final Account testAccount = new Account(calendarName, accountType);
|
||||
|
||||
Uri calendarURI;
|
||||
LocalCalendar testCalendar;
|
||||
@ -69,7 +69,7 @@ public class LocalCalendarTest extends InstrumentationTestCase {
|
||||
build();
|
||||
}
|
||||
|
||||
private long insertNewEvent() throws LocalStorageException, RemoteException {
|
||||
private long insertNewEvent() throws RemoteException {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Events.CALENDAR_ID, testCalendar.getId());
|
||||
values.put(Events.TITLE, "Test Event");
|
||||
|
@ -13,14 +13,12 @@ import android.test.InstrumentationTestCase;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGetHC4;
|
||||
import org.apache.http.client.methods.HttpPostHC4;
|
||||
import org.apache.http.client.methods.HttpRequestBaseHC4;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import at.bitfire.davdroid.TestConstants;
|
||||
import lombok.Cleanup;
|
||||
|
||||
public class DavHttpClientTest extends InstrumentationTestCase {
|
||||
final static URI testCookieURI = TestConstants.roboHydra.resolve("/dav/testCookieStore");
|
||||
|
@ -25,7 +25,7 @@ import at.bitfire.davdroid.TestConstants;
|
||||
public class DavRedirectStrategyTest extends TestCase {
|
||||
|
||||
CloseableHttpClient httpClient;
|
||||
DavRedirectStrategy strategy = DavRedirectStrategy.INSTANCE;
|
||||
final DavRedirectStrategy strategy = DavRedirectStrategy.INSTANCE;
|
||||
|
||||
@Override
|
||||
protected void setUp() {
|
||||
|
@ -12,8 +12,8 @@ import android.util.Log;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.http.HttpHost;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -29,7 +29,7 @@ import lombok.Cleanup;
|
||||
public class TlsSniSocketFactoryTest extends TestCase {
|
||||
private static final String TAG = "davdroid.TlsSniSocketFactoryTest";
|
||||
|
||||
TlsSniSocketFactory factory = TlsSniSocketFactory.getSocketFactory();
|
||||
final TlsSniSocketFactory factory = TlsSniSocketFactory.getSocketFactory();
|
||||
|
||||
private InetSocketAddress sampleTlsEndpoint;
|
||||
|
||||
@ -75,7 +75,7 @@ public class TlsSniSocketFactoryTest extends TestCase {
|
||||
}
|
||||
|
||||
public void testProtocolVersions() throws IOException {
|
||||
String enabledProtocols[] = factory.protocols;
|
||||
String enabledProtocols[] = TlsSniSocketFactory.protocols;
|
||||
// SSL (all versions) should be disabled
|
||||
for (String protocol : enabledProtocols)
|
||||
assertFalse(protocol.contains("SSL"));
|
||||
|
@ -28,9 +28,7 @@ import lombok.Cleanup;
|
||||
// tests require running robohydra!
|
||||
|
||||
public class WebDavResourceTest extends InstrumentationTestCase {
|
||||
static byte[] SAMPLE_CONTENT = new byte[] { 1, 2, 3, 4, 5 };
|
||||
|
||||
final static String PATH_SIMPLE_FILE = "collection/new.file";
|
||||
final static byte[] SAMPLE_CONTENT = new byte[] { 1, 2, 3, 4, 5 };
|
||||
|
||||
AssetManager assetMgr;
|
||||
CloseableHttpClient httpClient;
|
||||
|
@ -7,6 +7,7 @@
|
||||
*/
|
||||
package at.bitfire.davdroid;
|
||||
|
||||
import net.fortuna.ical4j.model.Calendar;
|
||||
import net.fortuna.ical4j.model.property.ProdId;
|
||||
|
||||
public class Constants {
|
||||
@ -16,5 +17,5 @@ public class Constants {
|
||||
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";
|
||||
|
||||
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");
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import net.fortuna.ical4j.model.DefaultTimeZoneRegistryFactory;
|
||||
import net.fortuna.ical4j.model.TimeZone;
|
||||
import net.fortuna.ical4j.model.TimeZoneRegistry;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.SimpleTimeZone;
|
||||
|
||||
|
@ -9,11 +9,6 @@ package at.bitfire.davdroid;
|
||||
|
||||
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.URISyntaxException;
|
||||
|
||||
|
@ -7,7 +7,6 @@
|
||||
*/
|
||||
package at.bitfire.davdroid.resource;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.util.Log;
|
||||
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
@ -17,7 +16,6 @@ import org.simpleframework.xml.core.Persister;
|
||||
import java.io.StringWriter;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
||||
import at.bitfire.davdroid.webdav.DavCalendarQuery;
|
||||
import at.bitfire.davdroid.webdav.DavCompFilter;
|
||||
import at.bitfire.davdroid.webdav.DavFilter;
|
||||
|
@ -7,8 +7,6 @@
|
||||
*/
|
||||
package at.bitfire.davdroid.resource;
|
||||
|
||||
import android.accounts.Account;
|
||||
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
|
@ -9,20 +9,14 @@ package at.bitfire.davdroid.resource;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import net.fortuna.ical4j.model.property.ProdId;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import at.bitfire.davdroid.Constants;
|
||||
@ -30,7 +24,6 @@ import ezvcard.Ezvcard;
|
||||
import ezvcard.VCard;
|
||||
import ezvcard.VCardVersion;
|
||||
import ezvcard.ValidationWarnings;
|
||||
import ezvcard.Warning;
|
||||
import ezvcard.parameter.EmailType;
|
||||
import ezvcard.parameter.ImageType;
|
||||
import ezvcard.parameter.RelatedType;
|
||||
@ -59,8 +52,6 @@ import ezvcard.property.Telephone;
|
||||
import ezvcard.property.Title;
|
||||
import ezvcard.property.Uid;
|
||||
import ezvcard.property.Url;
|
||||
import ezvcard.property.VCardProperty;
|
||||
import ezvcard.util.ListMultimap;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
@ -265,7 +256,7 @@ public class Contact extends Resource {
|
||||
}
|
||||
|
||||
// NOTE
|
||||
List<String> notes = new LinkedList<String>();
|
||||
List<String> notes = new LinkedList<>();
|
||||
for (Note note : vcard.getNotes())
|
||||
notes.add(note.getValue());
|
||||
if (!notes.isEmpty())
|
||||
@ -420,7 +411,7 @@ public class Contact extends Resource {
|
||||
|
||||
// CATEGORY
|
||||
if (!categories.isEmpty())
|
||||
vcard.setCategories(categories.toArray(new String[0]));
|
||||
vcard.setCategories(categories.toArray(new String[categories.size()]));
|
||||
|
||||
// URL
|
||||
for (String url : URLs)
|
||||
|
@ -9,7 +9,6 @@ package at.bitfire.davdroid.resource;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
@ -22,7 +21,6 @@ import org.xbill.DNS.Type;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.LinkedList;
|
||||
@ -40,8 +38,8 @@ import ezvcard.VCardVersion;
|
||||
public class DavResourceFinder implements Closeable {
|
||||
private final static String TAG = "davdroid.ResourceFinder";
|
||||
|
||||
protected Context context;
|
||||
protected CloseableHttpClient httpClient;
|
||||
final protected Context context;
|
||||
final protected CloseableHttpClient httpClient;
|
||||
|
||||
|
||||
public DavResourceFinder(Context context) {
|
||||
@ -187,10 +185,9 @@ public class DavResourceFinder implements Closeable {
|
||||
* @param serviceName Service name ("carddav" or "caldav")
|
||||
* @return Initial service URL (HTTP/HTTPS), without user credentials
|
||||
* @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 {
|
||||
String scheme = null,
|
||||
public URI getInitialContextURL(ServerInfo serverInfo, String serviceName) throws URISyntaxException {
|
||||
String scheme,
|
||||
domain;
|
||||
int port = -1;
|
||||
String path = "/";
|
||||
|
@ -38,7 +38,6 @@ import net.fortuna.ical4j.model.property.ExRule;
|
||||
import net.fortuna.ical4j.model.property.LastModified;
|
||||
import net.fortuna.ical4j.model.property.Location;
|
||||
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.RRule;
|
||||
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.UidGenerator;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SimpleTimeZone;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import at.bitfire.davdroid.Constants;
|
||||
@ -98,9 +93,9 @@ public class Event extends Resource {
|
||||
@Getter @Setter protected boolean opaque;
|
||||
|
||||
@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 {
|
||||
CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_UNFOLDING, true);
|
||||
@ -201,10 +196,10 @@ public class Event extends Resource {
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
if (event.getSummary() != null)
|
||||
@ -218,7 +213,7 @@ public class Event extends Resource {
|
||||
opaque = event.getTransparency() != Transp.TRANSPARENT;
|
||||
|
||||
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);
|
||||
|
||||
Clazz classification = event.getClassification();
|
||||
|
@ -41,21 +41,17 @@ import android.provider.ContactsContract.RawContacts;
|
||||
import android.util.Log;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
||||
@ -64,7 +60,6 @@ import ezvcard.parameter.EmailType;
|
||||
import ezvcard.parameter.ImppType;
|
||||
import ezvcard.parameter.RelatedType;
|
||||
import ezvcard.parameter.TelephoneType;
|
||||
import ezvcard.parameter.VCardParameter;
|
||||
import ezvcard.property.Address;
|
||||
import ezvcard.property.Anniversary;
|
||||
import ezvcard.property.Birthday;
|
||||
@ -81,7 +76,7 @@ public class LocalAddressBook extends LocalCollection<Contact> {
|
||||
protected final static String COLUMN_UNKNOWN_PROPERTIES = RawContacts.SYNC3;
|
||||
|
||||
|
||||
protected AccountSettings accountSettings;
|
||||
final protected AccountSettings accountSettings;
|
||||
|
||||
|
||||
/* database fields */
|
||||
@ -138,7 +133,7 @@ public class LocalAddressBook extends LocalCollection<Contact> {
|
||||
return c;
|
||||
}
|
||||
|
||||
public void deleteAllExceptRemoteNames(Resource[] remoteResources) {
|
||||
public int deleteAllExceptRemoteNames(Resource[] remoteResources) throws LocalStorageException {
|
||||
String where;
|
||||
|
||||
if (remoteResources.length != 0) {
|
||||
@ -149,15 +144,16 @@ public class LocalAddressBook extends LocalCollection<Contact> {
|
||||
} else
|
||||
where = entryColumnRemoteName() + " IS NOT NULL";
|
||||
|
||||
Builder builder = ContentProviderOperation.newDelete(entriesURI()).withSelection(where, null);
|
||||
pendingOperations.add(builder
|
||||
.withYieldAllowed(true)
|
||||
.build());
|
||||
}
|
||||
try {
|
||||
return providerClient.delete(entriesURI(), where, null);
|
||||
} catch (RemoteException e) {
|
||||
throw new LocalStorageException("Couldn't delete contacts locally", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit() throws LocalStorageException {
|
||||
super.commit();
|
||||
public int commit() throws LocalStorageException {
|
||||
int affected = super.commit();
|
||||
|
||||
// update group details for groups we have just created
|
||||
Uri groupsUri = syncAdapterURI(Groups.CONTENT_URI);
|
||||
@ -175,11 +171,13 @@ public class LocalAddressBook extends LocalCollection<Contact> {
|
||||
.withValue(Groups.TITLE, sourceID)
|
||||
.withValue(Groups.GROUP_VISIBLE, 1)
|
||||
.build());
|
||||
super.commit();
|
||||
affected += super.commit();
|
||||
}
|
||||
} catch (RemoteException 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)");
|
||||
}
|
||||
|
||||
protected void populateURL(Contact c, ContentValues row) throws RemoteException {
|
||||
protected void populateURL(Contact c, ContentValues row) {
|
||||
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);
|
||||
try {
|
||||
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);
|
||||
|
||||
// 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 {
|
||||
Impp impp = new Impp("sip:" + row.getAsString(SipAddress.SIP_ADDRESS));
|
||||
switch (row.getAsInteger(SipAddress.TYPE)) {
|
||||
@ -971,11 +969,11 @@ public class LocalAddressBook extends LocalCollection<Contact> {
|
||||
lineLocality = StringUtils.join(new String[] { address.getPostalCode(), address.getLocality() }, " ");
|
||||
|
||||
List<String> lines = new LinkedList<>();
|
||||
if (lineStreet != null)
|
||||
if (StringUtils.isNotBlank(lineStreet))
|
||||
lines.add(lineStreet);
|
||||
if (address.getRegion() != null && !address.getRegion().isEmpty())
|
||||
lines.add(address.getRegion());
|
||||
if (lineLocality != null)
|
||||
if (StringUtils.isNotBlank(lineLocality))
|
||||
lines.add(lineLocality);
|
||||
|
||||
formattedAddress = StringUtils.join(lines, "\n");
|
||||
@ -1088,7 +1086,7 @@ public class LocalAddressBook extends LocalCollection<Contact> {
|
||||
String lowerCase = StringUtils.lowerCase(xname, Locale.US),
|
||||
withoutPrefix = StringUtils.removeStart(lowerCase, "x-"),
|
||||
withSpaces = StringUtils.replace(withoutPrefix, "_", " ");
|
||||
return WordUtils.capitalize(withSpaces);
|
||||
return StringUtils.capitalize(withSpaces);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,21 +28,14 @@ import android.provider.CalendarContract.Attendees;
|
||||
import android.provider.CalendarContract.Calendars;
|
||||
import android.provider.CalendarContract.Events;
|
||||
import android.provider.CalendarContract.Reminders;
|
||||
import android.provider.ContactsContract;
|
||||
import android.util.Log;
|
||||
|
||||
import net.fortuna.ical4j.model.Date;
|
||||
import net.fortuna.ical4j.model.DateList;
|
||||
import net.fortuna.ical4j.model.DateTime;
|
||||
import net.fortuna.ical4j.model.Dur;
|
||||
import net.fortuna.ical4j.model.Parameter;
|
||||
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.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.parameter.Cn;
|
||||
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.Attendee;
|
||||
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.Duration;
|
||||
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.RecurrenceId;
|
||||
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.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.text.ParseException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import at.bitfire.davdroid.DAVUtils;
|
||||
import at.bitfire.davdroid.DateUtils;
|
||||
@ -91,7 +78,7 @@ public class LocalCalendar extends LocalCollection<Event> {
|
||||
@Getter protected String url;
|
||||
@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 */
|
||||
@ -118,7 +105,7 @@ public class LocalCalendar extends LocalCollection<Event> {
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
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)
|
||||
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()]);
|
||||
}
|
||||
|
||||
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);
|
||||
this.id = id;
|
||||
this.url = url;
|
||||
@ -229,7 +216,7 @@ public class LocalCalendar extends LocalCollection<Event> {
|
||||
return new Event(localID, resourceName, eTag);
|
||||
}
|
||||
|
||||
public void deleteAllExceptRemoteNames(Resource[] remoteResources) {
|
||||
public int deleteAllExceptRemoteNames(Resource[] remoteResources) throws LocalStorageException {
|
||||
List<String> sqlFileNames = new LinkedList<>();
|
||||
for (Resource res : remoteResources)
|
||||
sqlFileNames.add(DatabaseUtils.sqlEscapeString(res.getName()));
|
||||
@ -256,6 +243,7 @@ public class LocalCalendar extends LocalCollection<Event> {
|
||||
.withYieldAllowed(true)
|
||||
.build()
|
||||
);
|
||||
return commit();
|
||||
}
|
||||
|
||||
@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 {
|
||||
Attendee attendee = new Attendee(new URI("mailto", values.getAsString(Attendees.ATTENDEE_EMAIL), null));
|
||||
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));
|
||||
|
||||
PropertyList props = alarm.getProperties();
|
||||
|
@ -11,6 +11,7 @@ import android.accounts.Account;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentProviderOperation.Builder;
|
||||
import android.content.ContentProviderResult;
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.OperationApplicationException;
|
||||
@ -21,14 +22,13 @@ import android.os.RemoteException;
|
||||
import android.provider.CalendarContract;
|
||||
import android.util.Log;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Cleanup;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Represents a locally-stored synchronizable collection (for instance, the
|
||||
@ -40,9 +40,9 @@ import lombok.Getter;
|
||||
public abstract class LocalCollection<T extends Resource> {
|
||||
private static final String TAG = "davdroid.Collection";
|
||||
|
||||
protected Account account;
|
||||
protected ContentProviderClient providerClient;
|
||||
protected ArrayList<ContentProviderOperation> pendingOperations = new ArrayList<ContentProviderOperation>();
|
||||
final protected Account account;
|
||||
final protected ContentProviderClient providerClient;
|
||||
final protected ArrayList<ContentProviderOperation> pendingOperations = new ArrayList<>();
|
||||
|
||||
|
||||
// database fields
|
||||
@ -269,8 +269,8 @@ public abstract class LocalCollection<T extends Resource> {
|
||||
* @return the new resource object */
|
||||
abstract public T newResource(long localID, String resourceName, String eTag);
|
||||
|
||||
/** Enqueues adding the resource (including all data) to the local collection. Requires commit(). */
|
||||
public void add(Resource resource) {
|
||||
/** Enqueues adding the resource (including all data) to the local collection. */
|
||||
public void add(Resource resource) throws LocalStorageException {
|
||||
int idx = pendingOperations.size();
|
||||
pendingOperations.add(
|
||||
buildEntry(ContentProviderOperation.newInsert(entriesURI()), resource, false)
|
||||
@ -278,6 +278,7 @@ public abstract class LocalCollection<T extends Resource> {
|
||||
.build());
|
||||
|
||||
addDataRows(resource, -1, idx);
|
||||
commit();
|
||||
}
|
||||
|
||||
/** 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);
|
||||
addDataRows(remoteResource, localResource.getLocalID(), -1);
|
||||
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
|
||||
* @return number of deleted resources
|
||||
*/
|
||||
public void deleteAllExceptRemoteNames(Resource[] remoteResources) {
|
||||
public int deleteAllExceptRemoteNames(Resource[] remoteResources) throws LocalStorageException {
|
||||
final String where;
|
||||
|
||||
if (remoteResources.length != 0) {
|
||||
@ -319,13 +322,17 @@ public abstract class LocalCollection<T extends Resource> {
|
||||
// delete all entries
|
||||
where = entryColumnRemoteName() + " IS NOT NULL";
|
||||
|
||||
ContentProviderOperation.Builder builder = ContentProviderOperation.newDelete(entriesURI())
|
||||
.withSelection( // restrict deletion to parent collection
|
||||
entryColumnParentID() + "=? AND (" + where + ')',
|
||||
new String[] { String.valueOf(getId()) }
|
||||
);
|
||||
pendingOperations.add(builder.withYieldAllowed(true).build());
|
||||
}
|
||||
try {
|
||||
return providerClient.delete(
|
||||
entriesURI(),
|
||||
// restrict deletion to parent collection
|
||||
entryColumnParentID() + "=? AND (" + where + ')',
|
||||
new String[] { String.valueOf(getId()) }
|
||||
);
|
||||
} catch (RemoteException e) {
|
||||
throw new LocalStorageException("Couldn't delete local resources", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Updates the locally-known ETag of a resource. */
|
||||
@ -350,17 +357,21 @@ public abstract class LocalCollection<T extends Resource> {
|
||||
}
|
||||
|
||||
/** 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())
|
||||
try {
|
||||
Log.d(TAG, "Committing " + pendingOperations.size() + " operations");
|
||||
providerClient.applyBatch(pendingOperations);
|
||||
Log.d(TAG, "Committing " + pendingOperations.size() + " operations ...");
|
||||
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();
|
||||
} catch (RemoteException ex) {
|
||||
throw new LocalStorageException(ex);
|
||||
} catch(OperationApplicationException ex) {
|
||||
} catch(OperationApplicationException | RemoteException ex) {
|
||||
throw new LocalStorageException(ex);
|
||||
}
|
||||
return affected;
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,17 +24,15 @@ import net.fortuna.ical4j.model.Date;
|
||||
import net.fortuna.ical4j.model.DateTime;
|
||||
import net.fortuna.ical4j.model.Dur;
|
||||
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.Completed;
|
||||
import net.fortuna.ical4j.model.property.Created;
|
||||
import net.fortuna.ical4j.model.property.DtStart;
|
||||
import net.fortuna.ical4j.model.property.Due;
|
||||
import net.fortuna.ical4j.model.property.Duration;
|
||||
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 org.dmfs.provider.tasks.TaskContract;
|
||||
|
||||
import java.util.LinkedList;
|
||||
@ -52,7 +50,7 @@ public class LocalTaskList extends LocalCollection<Task> {
|
||||
|
||||
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 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 {
|
||||
final ContentProviderClient client = resolver.acquireContentProviderClient(TASKS_AUTHORITY);
|
||||
@Cleanup("release") final ContentProviderClient client = resolver.acquireContentProviderClient(TASKS_AUTHORITY);
|
||||
if (client == null)
|
||||
throw new LocalStorageException("No tasks provider found");
|
||||
|
||||
@ -101,7 +99,7 @@ public class LocalTaskList extends LocalCollection<Task> {
|
||||
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);
|
||||
this.id = id;
|
||||
this.url = url;
|
||||
|
@ -17,10 +17,6 @@ public class RecordNotFoundException extends LocalStorageException {
|
||||
private static final String detailMessage = "Record not found in local content provider";
|
||||
|
||||
|
||||
RecordNotFoundException(Throwable ex) {
|
||||
super(detailMessage, ex);
|
||||
}
|
||||
|
||||
RecordNotFoundException() {
|
||||
super(detailMessage);
|
||||
}
|
||||
|
@ -7,11 +7,8 @@
|
||||
*/
|
||||
package at.bitfire.davdroid.resource;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.util.Log;
|
||||
|
||||
import net.fortuna.ical4j.model.ValidationException;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
|
||||
@ -25,10 +22,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
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.DavFilter;
|
||||
import at.bitfire.davdroid.webdav.DavMultiget;
|
||||
import at.bitfire.davdroid.webdav.DavNoContentException;
|
||||
import at.bitfire.davdroid.webdav.HttpException;
|
||||
@ -38,7 +32,6 @@ import at.bitfire.davdroid.webdav.WebDavResource.PutMode;
|
||||
import ezvcard.io.text.VCardParseException;
|
||||
import lombok.Cleanup;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Represents a remotely stored synchronizable collection (collection as in
|
||||
@ -49,7 +42,6 @@ import lombok.Setter;
|
||||
public abstract class RemoteCollection<T extends Resource> {
|
||||
private static final String TAG = "davdroid.resource";
|
||||
|
||||
CloseableHttpClient httpClient;
|
||||
URI baseURI;
|
||||
@Getter WebDavResource collection;
|
||||
|
||||
@ -59,8 +51,6 @@ public abstract class RemoteCollection<T extends Resource> {
|
||||
abstract protected T newResourceSkeleton(String name, String ETag);
|
||||
|
||||
public RemoteCollection(CloseableHttpClient httpClient, String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException {
|
||||
this.httpClient = httpClient;
|
||||
|
||||
baseURI = URIUtils.parseURI(baseURL, false);
|
||||
collection = new WebDavResource(httpClient, baseURI, user, password, preemptiveAuth);
|
||||
}
|
||||
@ -101,12 +91,12 @@ public abstract class RemoteCollection<T extends Resource> {
|
||||
else
|
||||
collection.propfind(HttpPropfind.Mode.MEMBERS_ETAG);
|
||||
|
||||
List<T> resources = new LinkedList<T>();
|
||||
List<T> resources = new LinkedList<>();
|
||||
if (collection.getMembers() != null)
|
||||
for (WebDavResource member : collection.getMembers())
|
||||
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 {
|
||||
try {
|
||||
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)");
|
||||
|
||||
LinkedList<String> names = new LinkedList<String>();
|
||||
LinkedList<String> names = new LinkedList<>();
|
||||
for (Resource resource : resources)
|
||||
names.add(resource.getName());
|
||||
|
||||
LinkedList<T> foundResources = new LinkedList<T>();
|
||||
collection.multiGet(multiGetType(), names.toArray(new String[0]));
|
||||
LinkedList<T> foundResources = new LinkedList<>();
|
||||
collection.multiGet(multiGetType(), names.toArray(new String[names.size()]));
|
||||
if (collection.getMembers() == null)
|
||||
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) {
|
||||
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
|
||||
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());
|
||||
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
|
||||
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());
|
||||
member.setContentType(res.getMimeType());
|
||||
|
||||
@ -211,22 +201,22 @@ public abstract class RemoteCollection<T extends Resource> {
|
||||
|
||||
Resource.AssetDownloader getDownloader() {
|
||||
return new Resource.AssetDownloader() {
|
||||
@Override
|
||||
public byte[] download(URI uri) throws URISyntaxException, IOException, HttpException, DavException {
|
||||
if (!uri.isAbsolute())
|
||||
throw new URISyntaxException(uri.toString(), "URI referenced from entity must be absolute");
|
||||
@Override
|
||||
public byte[] download(URI uri) throws URISyntaxException, IOException, HttpException, DavException {
|
||||
if (!uri.isAbsolute())
|
||||
throw new URISyntaxException(uri.toString(), "URI referenced from entity must be absolute");
|
||||
|
||||
if (uri.getScheme().equalsIgnoreCase(baseURI.getScheme()) &&
|
||||
uri.getAuthority().equalsIgnoreCase(baseURI.getAuthority())) {
|
||||
// resource is on same server, send Authorization
|
||||
WebDavResource file = new WebDavResource(collection, uri);
|
||||
file.get("image/*");
|
||||
return file.getContent();
|
||||
} else {
|
||||
// resource is on an external server, don't send Authorization
|
||||
return IOUtils.toByteArray(uri);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (uri.getScheme().equalsIgnoreCase(baseURI.getScheme()) &&
|
||||
uri.getAuthority().equalsIgnoreCase(baseURI.getAuthority())) {
|
||||
// resource is on same server, send Authorization
|
||||
WebDavResource file = new WebDavResource(collection, uri);
|
||||
file.get("image/*");
|
||||
return file.getContent();
|
||||
} else {
|
||||
// resource is on an external server, don't send Authorization
|
||||
return IOUtils.toByteArray(uri);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
import at.bitfire.davdroid.webdav.DavException;
|
||||
import at.bitfire.davdroid.webdav.HttpException;
|
||||
@ -58,6 +57,6 @@ public abstract class Resource {
|
||||
|
||||
|
||||
public interface AssetDownloader {
|
||||
public byte[] download(URI url) throws URISyntaxException, IOException, HttpException, DavException;
|
||||
byte[] download(URI url) throws URISyntaxException, IOException, HttpException, DavException;
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@
|
||||
*/
|
||||
package at.bitfire.davdroid.resource;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.util.LinkedList;
|
||||
@ -20,10 +19,6 @@ import lombok.RequiredArgsConstructor;
|
||||
@RequiredArgsConstructor(suppressConstructorProperties=true)
|
||||
@Data
|
||||
public class ServerInfo {
|
||||
enum Scheme {
|
||||
HTTP, HTTPS, MAILTO
|
||||
}
|
||||
|
||||
final private URI baseURI;
|
||||
final private String userName, password;
|
||||
final boolean authPreemptive;
|
||||
|
@ -38,7 +38,7 @@ public class AccountAuthenticatorService extends Service {
|
||||
|
||||
|
||||
private static class AccountAuthenticator extends AbstractAccountAuthenticator {
|
||||
Context context;
|
||||
final Context context;
|
||||
|
||||
public AccountAuthenticator(Context context) {
|
||||
super(context);
|
||||
|
@ -19,7 +19,6 @@ import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.CalendarContract;
|
||||
import android.provider.CalendarContract.Calendars;
|
||||
import android.provider.ContactsContract;
|
||||
import android.util.Log;
|
||||
|
||||
import java.net.URI;
|
||||
@ -46,9 +45,9 @@ public class AccountSettings {
|
||||
|
||||
public final static long SYNC_INTERVAL_MANUALLY = -1;
|
||||
|
||||
Context context;
|
||||
AccountManager accountManager;
|
||||
Account account;
|
||||
final Context context;
|
||||
final AccountManager accountManager;
|
||||
final Account account;
|
||||
|
||||
|
||||
public AccountSettings(Context context, Account account) {
|
||||
@ -78,7 +77,7 @@ public class AccountSettings {
|
||||
if (addressBook.isEnabled()) {
|
||||
bundle.putString(KEY_ADDRESSBOOK_URL, addressBook.getURL());
|
||||
bundle.putString(KEY_ADDRESSBOOK_VCARD_VERSION, addressBook.getVCardVersion().getVersion());
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ public class CalendarsSyncAdapterService extends Service {
|
||||
boolean preemptive = settings.getPreemptiveAuth();
|
||||
|
||||
try {
|
||||
Map<LocalCollection<?>, RemoteCollection<?>> map = new HashMap<LocalCollection<?>, RemoteCollection<?>>();
|
||||
Map<LocalCollection<?>, RemoteCollection<?>> map = new HashMap<>();
|
||||
|
||||
for (LocalCalendar calendar : LocalCalendar.findAll(account, provider)) {
|
||||
RemoteCollection<?> dav = new CalDavCalendar(httpClient, calendar.getUrl(), userName, password, preemptive);
|
||||
|
@ -67,7 +67,7 @@ public class ContactsSyncAdapterService extends Service {
|
||||
LocalCollection<?> database = new LocalAddressBook(account, provider, settings);
|
||||
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);
|
||||
|
||||
return map;
|
||||
|
@ -8,8 +8,6 @@
|
||||
package at.bitfire.davdroid.syncadapter;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
@ -19,17 +17,15 @@ import android.content.ContentProviderClient;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SyncResult;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.Settings;
|
||||
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.impl.client.CloseableHttpClient;
|
||||
|
||||
@ -57,7 +53,7 @@ public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter impleme
|
||||
|
||||
@Getter private static String androidID;
|
||||
|
||||
protected Context context;
|
||||
final protected Context context;
|
||||
|
||||
/* We use one static httpClient for
|
||||
* - all sync adapters (CalendarsSyncAdapter, ContactsSyncAdapter)
|
||||
@ -120,7 +116,6 @@ public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter impleme
|
||||
httpClientLock.writeLock().lock();
|
||||
if (httpClient == null) {
|
||||
Log.d(TAG, "Creating new DavHttpClient");
|
||||
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
httpClient = DavHttpClient.create();
|
||||
}
|
||||
|
||||
@ -129,10 +124,6 @@ public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter impleme
|
||||
httpClientLock.readLock().lock();
|
||||
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
|
||||
Intent exceptionIntent = null; // what shall happen when clicking on the exception notification
|
||||
try {
|
||||
@ -199,7 +190,7 @@ public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter impleme
|
||||
.setContentTitle(context.getString(R.string.sync_error_title))
|
||||
.setContentText(exceptionToShow.getLocalizedMessage())
|
||||
.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);
|
||||
|
||||
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
@ -10,8 +10,6 @@ package at.bitfire.davdroid.syncadapter;
|
||||
import android.content.SyncResult;
|
||||
import android.util.Log;
|
||||
|
||||
import net.fortuna.ical4j.model.ValidationException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashSet;
|
||||
@ -33,8 +31,8 @@ public class SyncManager {
|
||||
|
||||
private static final int MAX_MULTIGET_RESOURCES = 35;
|
||||
|
||||
protected LocalCollection<? extends Resource> local;
|
||||
protected RemoteCollection<? extends Resource> remote;
|
||||
final protected LocalCollection<? extends Resource> local;
|
||||
final protected RemoteCollection<? extends Resource> remote;
|
||||
|
||||
|
||||
public SyncManager(LocalCollection<? extends Resource> local, RemoteCollection<? extends Resource> remote) {
|
||||
@ -49,10 +47,8 @@ public class SyncManager {
|
||||
addedRemotely = pushNew(),
|
||||
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)
|
||||
boolean fetchCollection = syncResult.stats.numEntries > 0;
|
||||
boolean fetchCollection = (deletedRemotely + addedRemotely + updatedRemotely) > 0;
|
||||
if (manualSync) {
|
||||
Log.i(TAG, "Synchronization forced");
|
||||
fetchCollection = true;
|
||||
@ -72,8 +68,8 @@ public class SyncManager {
|
||||
|
||||
// PHASE 2B: detect details of remote changes
|
||||
Log.i(TAG, "Fetching remote resource list");
|
||||
Set<Resource> remotelyAdded = new HashSet<Resource>(),
|
||||
remotelyUpdated = new HashSet<Resource>();
|
||||
Set<Resource> remotelyAdded = new HashSet<>(),
|
||||
remotelyUpdated = new HashSet<>();
|
||||
|
||||
Resource[] remoteResources = remote.getMemberETags();
|
||||
for (Resource remoteResource : remoteResources) {
|
||||
@ -87,13 +83,13 @@ public class SyncManager {
|
||||
}
|
||||
|
||||
// PHASE 3: pull remote changes from server
|
||||
syncResult.stats.numInserts = pullNew(remotelyAdded.toArray(new Resource[0]));
|
||||
syncResult.stats.numUpdates = pullChanged(remotelyUpdated.toArray(new Resource[0]));
|
||||
syncResult.stats.numEntries += syncResult.stats.numInserts + syncResult.stats.numUpdates;
|
||||
syncResult.stats.numInserts = pullNew(remotelyAdded.toArray(new Resource[remotelyAdded.size()]));
|
||||
syncResult.stats.numUpdates = pullChanged(remotelyUpdated.toArray(new Resource[remotelyUpdated.size()]));
|
||||
|
||||
Log.i(TAG, "Removing non-dirty resources that are not present remotely anymore");
|
||||
local.deleteAllExceptRemoteNames(remoteResources);
|
||||
local.commit();
|
||||
syncResult.stats.numDeletes = local.deleteAllExceptRemoteNames(remoteResources);
|
||||
|
||||
syncResult.stats.numEntries = syncResult.stats.numInserts + syncResult.stats.numUpdates + syncResult.stats.numDeletes;
|
||||
|
||||
// update collection CTag
|
||||
Log.i(TAG, "Sync complete, fetching new CTag");
|
||||
@ -145,10 +141,8 @@ public class SyncManager {
|
||||
local.updateETag(res, eTag);
|
||||
local.clearDirty(res);
|
||||
count++;
|
||||
} catch(PreconditionFailedException e) {
|
||||
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 (PreconditionFailedException e) {
|
||||
Log.i(TAG, "Didn't overwrite existing resource with other content");
|
||||
} catch (RecordNotFoundException e) {
|
||||
Log.wtf(TAG, "Couldn't read new record", e);
|
||||
}
|
||||
@ -171,10 +165,8 @@ public class SyncManager {
|
||||
local.updateETag(res, eTag);
|
||||
local.clearDirty(res);
|
||||
count++;
|
||||
} catch(PreconditionFailedException e) {
|
||||
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 (PreconditionFailedException e) {
|
||||
Log.i(TAG, "Locally changed resource has been changed on the server in the meanwhile");
|
||||
} catch (RecordNotFoundException e) {
|
||||
Log.e(TAG, "Couldn't read dirty record", e);
|
||||
}
|
||||
@ -193,7 +185,6 @@ public class SyncManager {
|
||||
for (Resource res : remote.multiGet(resources)) {
|
||||
Log.d(TAG, "Adding " + res.getName());
|
||||
local.add(res);
|
||||
local.commit();
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
@ -207,7 +198,6 @@ public class SyncManager {
|
||||
for (Resource res : remote.multiGet(resources)) {
|
||||
Log.i(TAG, "Updating " + res.getName());
|
||||
local.updateByRemoteName(res);
|
||||
local.commit();
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
|
@ -61,7 +61,7 @@ public class TasksSyncAdapterService extends Service {
|
||||
boolean preemptive = settings.getPreemptiveAuth();
|
||||
|
||||
try {
|
||||
Map<LocalCollection<?>, RemoteCollection<?>> map = new HashMap<LocalCollection<?>, RemoteCollection<?>>();
|
||||
Map<LocalCollection<?>, RemoteCollection<?>> map = new HashMap<>();
|
||||
|
||||
for (LocalTaskList calendar : LocalTaskList.findAll(account, provider)) {
|
||||
RemoteCollection<?> dav = new CalDavTaskList(httpClient, calendar.getUrl(), userName, password, preemptive);
|
||||
|
@ -22,8 +22,8 @@ import android.widget.TextView;
|
||||
|
||||
import at.bitfire.davdroid.Constants;
|
||||
import at.bitfire.davdroid.R;
|
||||
import at.bitfire.davdroid.ui.setup.AddAccountActivity;
|
||||
import at.bitfire.davdroid.ui.settings.SettingsActivity;
|
||||
import at.bitfire.davdroid.ui.setup.AddAccountActivity;
|
||||
|
||||
public class MainActivity extends Activity {
|
||||
|
||||
|
@ -12,7 +12,6 @@ import android.accounts.Account;
|
||||
import android.app.Activity;
|
||||
import android.app.FragmentManager;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import at.bitfire.davdroid.R;
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
package at.bitfire.davdroid.ui.settings;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.EditTextPreference;
|
||||
@ -20,13 +19,10 @@ import android.preference.SwitchPreference;
|
||||
import android.provider.CalendarContract;
|
||||
import android.provider.ContactsContract;
|
||||
|
||||
import org.dmfs.provider.tasks.TaskContract;
|
||||
|
||||
import at.bitfire.davdroid.R;
|
||||
import at.bitfire.davdroid.resource.LocalTaskList;
|
||||
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
||||
import ezvcard.VCardVersion;
|
||||
import lombok.Setter;
|
||||
|
||||
public class AccountFragment extends PreferenceFragment {
|
||||
final static String ARG_ACCOUNT = "account";
|
||||
|
@ -11,10 +11,8 @@ package at.bitfire.davdroid.ui.settings;
|
||||
import android.accounts.Account;
|
||||
import android.app.Activity;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.app.ListFragment;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.widget.ListView;
|
||||
|
||||
import at.bitfire.davdroid.R;
|
||||
|
||||
|
@ -32,7 +32,7 @@ public class SettingsScopeFragment extends ListFragment {
|
||||
final String[] accountNames = new String[accounts.length];
|
||||
for (int i = 0; i < accounts.length; i++)
|
||||
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);
|
||||
}
|
||||
|
@ -142,8 +142,7 @@ public class AccountDetailsFragment extends Fragment implements TextWatcher {
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
boolean ok = false;
|
||||
ok = editAccountName.getText().length() > 0;
|
||||
boolean ok = editAccountName.getText().length() > 0;
|
||||
MenuItem item = menu.findItem(R.id.add_account);
|
||||
item.setEnabled(ok);
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import at.bitfire.davdroid.Constants;
|
||||
import at.bitfire.davdroid.R;
|
||||
@ -45,11 +44,6 @@ public class AddAccountActivity extends Activity {
|
||||
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) {
|
||||
startActivityForResult(new Intent(Intent.ACTION_VIEW, Uri.parse(Constants.WEB_URL_HELP)), 0);
|
||||
}
|
||||
|
@ -8,20 +8,11 @@
|
||||
|
||||
package at.bitfire.davdroid.ui.setup;
|
||||
|
||||
import android.app.DialogFragment;
|
||||
import android.app.Fragment;
|
||||
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.Handler;
|
||||
import android.text.Html;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
@ -30,13 +21,9 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import at.bitfire.davdroid.Constants;
|
||||
import at.bitfire.davdroid.R;
|
||||
import at.bitfire.davdroid.resource.LocalTaskList;
|
||||
|
||||
public class InstallAppsFragment extends Fragment {
|
||||
private static final String TAG = "davdroid.setup";
|
||||
|
||||
// https://code.google.com/p/android/issues/detail?id=25906
|
||||
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
@ -68,8 +55,6 @@ public class InstallAppsFragment extends Fragment {
|
||||
}
|
||||
|
||||
protected void skip() {
|
||||
FragmentManager fm = getFragmentManager();
|
||||
|
||||
getFragmentManager().beginTransaction()
|
||||
.replace(R.id.right_pane, new SelectCollectionsFragment())
|
||||
.addToBackStack(null)
|
||||
|
@ -21,7 +21,7 @@ import at.bitfire.davdroid.R;
|
||||
|
||||
public class LoginTypeFragment extends Fragment {
|
||||
|
||||
protected RadioButton btnTypeEmail, btnTypeURL;
|
||||
protected RadioButton btnTypeEmail;
|
||||
|
||||
|
||||
@Override
|
||||
@ -29,7 +29,6 @@ public class LoginTypeFragment extends Fragment {
|
||||
View v = inflater.inflate(R.layout.setup_login_type, container, false);
|
||||
|
||||
btnTypeEmail = (RadioButton)v.findViewById(R.id.login_type_email);
|
||||
btnTypeURL = (RadioButton)v.findViewById(R.id.login_type_url);
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
|
@ -21,13 +21,12 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemSelectedListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
@ -40,7 +39,6 @@ public class LoginURLFragment extends Fragment implements TextWatcher {
|
||||
protected TextView textHttpWarning;
|
||||
protected EditText editBaseURI, editUserName, editPassword;
|
||||
protected CheckBox checkboxPreemptive;
|
||||
protected Button btnNext;
|
||||
|
||||
|
||||
@Override
|
||||
|
@ -18,10 +18,9 @@ import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.http.HttpException;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -44,8 +43,6 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC
|
||||
EXTRA_PASSWORD = "password",
|
||||
EXTRA_AUTH_PREEMPTIVE = "auth_preemptive";
|
||||
|
||||
ProgressBar progressBar;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
@ -44,8 +44,8 @@ public class SelectCollectionsAdapter extends BaseAdapter implements ListAdapter
|
||||
TYPE_TASK_LISTS_HEADING = 4,
|
||||
TYPE_TASK_LISTS_ROW = 5;
|
||||
|
||||
protected Context context;
|
||||
protected ServerInfo serverInfo;
|
||||
final protected Context context;
|
||||
final protected ServerInfo serverInfo;
|
||||
@Getter protected int
|
||||
nAddressBooks, nAddressBookHeadings,
|
||||
nCalendars, nCalendarHeadings,
|
||||
@ -160,7 +160,6 @@ public class SelectCollectionsAdapter extends BaseAdapter implements ListAdapter
|
||||
}
|
||||
|
||||
// step 2: fill view with content
|
||||
int collectionIcon;
|
||||
switch (viewType) {
|
||||
case TYPE_ADDRESS_BOOKS_ROW:
|
||||
setContent((CheckedTextView)v, R.drawable.addressbook, (ServerInfo.ResourceInfo)getItem(position));
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -11,7 +11,6 @@ package at.bitfire.davdroid.webdav;
|
||||
import org.simpleframework.xml.Attribute;
|
||||
import org.simpleframework.xml.Element;
|
||||
import org.simpleframework.xml.Namespace;
|
||||
import org.simpleframework.xml.Root;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -23,7 +22,7 @@ public class DavCompFilter {
|
||||
}
|
||||
|
||||
@Attribute(required=false)
|
||||
String name;
|
||||
final String name;
|
||||
|
||||
@Element(required=false,name="comp-filter")
|
||||
@Getter @Setter DavCompFilter compFilter;
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
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.impl.client.DefaultHttpRequestRetryHandlerHC4;
|
||||
|
||||
|
@ -49,7 +49,7 @@ public class DavMultiget {
|
||||
multiget.prop.calendarData = new DavProp.CalendarData();
|
||||
}
|
||||
|
||||
multiget.hrefs = new ArrayList<DavHref>(names.length);
|
||||
multiget.hrefs = new ArrayList<>(names.length);
|
||||
for (String name : names)
|
||||
multiget.hrefs.add(new DavHref(name));
|
||||
|
||||
|
@ -13,8 +13,6 @@ import org.simpleframework.xml.Root;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Root(strict=false)
|
||||
public class DavResponse {
|
||||
@Element
|
||||
|
@ -56,19 +56,19 @@ public class HttpPropfind extends HttpEntityEnclosingRequestBaseHC4 {
|
||||
depth = 1;
|
||||
propfind.prop.displayname = new DavProp.DisplayName();
|
||||
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.supportedAddressData = new LinkedList<DavProp.AddressDataType>();
|
||||
propfind.prop.supportedAddressData = new LinkedList<>();
|
||||
break;
|
||||
case CALDAV_COLLECTIONS:
|
||||
depth = 1;
|
||||
propfind.prop.displayname = new DavProp.DisplayName();
|
||||
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.calendarColor = new DavProp.CalendarColor();
|
||||
propfind.prop.calendarTimezone = new DavProp.CalendarTimezone();
|
||||
propfind.prop.supportedCalendarComponentSet = new LinkedList<DavProp.Comp>();
|
||||
propfind.prop.supportedCalendarComponentSet = new LinkedList<>();
|
||||
break;
|
||||
case COLLECTION_CTAG:
|
||||
propfind.prop.getctag = new DavProp.GetCTag();
|
||||
|
@ -11,7 +11,7 @@ package at.bitfire.davdroid.webdav;
|
||||
import android.os.Build;
|
||||
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.SSLConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.X509HostnameVerifier;
|
||||
@ -28,7 +28,7 @@ import javax.net.ssl.SSLSocketFactory;
|
||||
import lombok.Cleanup;
|
||||
|
||||
public class TlsSniSocketFactory extends SSLConnectionSocketFactory {
|
||||
private static final String TAG = "davdroid.TlsSniSocketFactory";
|
||||
private static final String TAG = "davdroid.TLS_SNI";
|
||||
|
||||
public static TlsSniSocketFactory getSocketFactory() {
|
||||
return new TlsSniSocketFactory(
|
||||
@ -48,41 +48,39 @@ public class TlsSniSocketFactory extends SSLConnectionSocketFactory {
|
||||
/* set reasonable protocol versions */
|
||||
// - 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
|
||||
List<String> protocols = new LinkedList<String>();
|
||||
List<String> protocols = new LinkedList<>();
|
||||
for (String protocol : socket.getSupportedProtocols())
|
||||
if (!protocol.toUpperCase().contains("SSL"))
|
||||
protocols.add(protocol);
|
||||
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 */
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
// choose secure cipher suites
|
||||
List<String> allowedCiphers = Arrays.asList(new String[]{
|
||||
// allowed secure ciphers according to NIST.SP.800-52r1.pdf Section 3.3.1 (see docs directory)
|
||||
// TLS 1.2
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECHDE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
// maximum interoperability
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
// additionally
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
});
|
||||
List<String> allowedCiphers = Arrays.asList(
|
||||
// TLS 1.2
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECHDE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
// maximum interoperability
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
// additionally
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");
|
||||
|
||||
List<String> availableCiphers = Arrays.asList(socket.getSupportedCipherSuites());
|
||||
|
||||
// preferred ciphers = allowed Ciphers \ availableCiphers
|
||||
HashSet<String> preferredCiphers = new HashSet<String>(allowedCiphers);
|
||||
HashSet<String> preferredCiphers = new HashSet<>(allowedCiphers);
|
||||
preferredCiphers.retainAll(availableCiphers);
|
||||
|
||||
// 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
|
||||
// ciphers should be a server-side task
|
||||
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, ", "));
|
||||
TlsSniSocketFactory.cipherSuites = enabledCiphers.toArray(new String[0]);
|
||||
TlsSniSocketFactory.cipherSuites = enabledCiphers.toArray(new String[enabledCiphers.size()]);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ package at.bitfire.davdroid.webdav;
|
||||
|
||||
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.HttpEntity;
|
||||
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.HttpPutHC4;
|
||||
import org.apache.http.client.protocol.HttpClientContext;
|
||||
import org.apache.http.client.utils.URIUtilsHC4;
|
||||
import org.apache.http.entity.ByteArrayEntityHC4;
|
||||
import org.apache.http.impl.auth.BasicSchemeHC4;
|
||||
import org.apache.http.impl.client.BasicAuthCache;
|
||||
@ -83,11 +82,11 @@ public class WebDavResource {
|
||||
@Getter protected URI location;
|
||||
|
||||
// DAV capabilities (DAV: header) and allowed DAV methods (set for OPTIONS request)
|
||||
protected Set<String> capabilities = new HashSet<String>(),
|
||||
methods = new HashSet<String>();
|
||||
protected Set<String> capabilities = new HashSet<>(),
|
||||
methods = new HashSet<>();
|
||||
|
||||
// DAV properties
|
||||
protected HashMap<Property, String> properties = new HashMap<Property, String>();
|
||||
protected HashMap<Property, String> properties = new HashMap<>();
|
||||
@Getter protected List<String> supportedComponents;
|
||||
|
||||
// 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
|
||||
for (int i = context.getRequestConfig().getMaxRedirects(); i > 0; i--) {
|
||||
// build multi-get XML request
|
||||
List<String> hrefs = new LinkedList<String>();
|
||||
List<String> hrefs = new LinkedList<>();
|
||||
for (String name : names)
|
||||
// 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
|
||||
// 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());
|
||||
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();
|
||||
try {
|
||||
@ -456,7 +455,7 @@ public class WebDavResource {
|
||||
return;
|
||||
|
||||
// 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)
|
||||
for (DavResponse singleResponse : multiStatus.response) {
|
||||
@ -470,7 +469,7 @@ public class WebDavResource {
|
||||
Log.d(TAG, "Processing multi-status element: " + href);
|
||||
|
||||
// process known properties
|
||||
HashMap<Property, String> properties = new HashMap<Property, String>();
|
||||
HashMap<Property, String> properties = new HashMap<>();
|
||||
List<String> supportedComponents = null;
|
||||
byte[] data = null;
|
||||
|
||||
@ -551,7 +550,7 @@ public class WebDavResource {
|
||||
}
|
||||
|
||||
if (prop.supportedCalendarComponentSet != null) {
|
||||
supportedComponents = new LinkedList<String>();
|
||||
supportedComponents = new LinkedList<>();
|
||||
for (Comp component : prop.supportedCalendarComponentSet)
|
||||
supportedComponents.add(component.getName());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user