mirror of
https://github.com/etesync/android
synced 2025-06-26 18:02:39 +00:00
Collections refresh
This commit is contained in:
parent
fc29988dc6
commit
af71ed8bc5
@ -7,6 +7,7 @@ import java.io.IOException;
|
|||||||
import at.bitfire.dav4android.exception.DavException;
|
import at.bitfire.dav4android.exception.DavException;
|
||||||
import at.bitfire.dav4android.exception.HttpException;
|
import at.bitfire.dav4android.exception.HttpException;
|
||||||
import at.bitfire.davdroid.Constants;
|
import at.bitfire.davdroid.Constants;
|
||||||
|
import at.bitfire.davdroid.ui.setup.DavResourceFinder;
|
||||||
import okhttp3.HttpUrl;
|
import okhttp3.HttpUrl;
|
||||||
import okhttp3.mockwebserver.MockResponse;
|
import okhttp3.mockwebserver.MockResponse;
|
||||||
import okhttp3.mockwebserver.MockWebServer;
|
import okhttp3.mockwebserver.MockWebServer;
|
||||||
|
@ -8,16 +8,45 @@
|
|||||||
|
|
||||||
package at.bitfire.davdroid;
|
package at.bitfire.davdroid;
|
||||||
|
|
||||||
|
import android.accounts.Account;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
|
import android.content.ContentValues;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.DatabaseUtils;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.database.sqlite.SQLiteException;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
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.Set;
|
||||||
|
|
||||||
|
import at.bitfire.dav4android.DavResource;
|
||||||
|
import at.bitfire.dav4android.UrlUtils;
|
||||||
|
import at.bitfire.dav4android.exception.DavException;
|
||||||
|
import at.bitfire.dav4android.exception.HttpException;
|
||||||
|
import at.bitfire.dav4android.exception.NotFoundException;
|
||||||
|
import at.bitfire.dav4android.property.AddressbookDescription;
|
||||||
|
import at.bitfire.dav4android.property.AddressbookHomeSet;
|
||||||
|
import at.bitfire.dav4android.property.CalendarDescription;
|
||||||
|
import at.bitfire.dav4android.property.CalendarHomeSet;
|
||||||
|
import at.bitfire.dav4android.property.DisplayName;
|
||||||
|
import at.bitfire.dav4android.property.ResourceType;
|
||||||
|
import at.bitfire.davdroid.model.CollectionInfo;
|
||||||
|
import at.bitfire.davdroid.model.ServiceDB.*;
|
||||||
|
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
||||||
|
import lombok.Cleanup;
|
||||||
|
import okhttp3.HttpUrl;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
|
||||||
public class DavService extends Service {
|
public class DavService extends Service {
|
||||||
|
|
||||||
public static final String
|
public static final String
|
||||||
@ -85,23 +114,177 @@ public class DavService extends Service {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
private class RefreshCollections implements Runnable {
|
private class RefreshCollections implements Runnable {
|
||||||
final long serviceId;
|
final long service;
|
||||||
|
final OpenHelper dbHelper;
|
||||||
|
SQLiteDatabase db;
|
||||||
|
|
||||||
RefreshCollections(long davServiceId) {
|
RefreshCollections(long davServiceId) {
|
||||||
this.serviceId = davServiceId;
|
this.service = davServiceId;
|
||||||
|
dbHelper = new OpenHelper(DavService.this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Constants.log.debug("RefreshCollections.Runner STARTING {}", serviceId);
|
|
||||||
try {
|
try {
|
||||||
Thread.currentThread().sleep(10000);
|
db = dbHelper.getWritableDatabase();
|
||||||
} catch (InterruptedException e) {
|
db.beginTransactionNonExclusive();
|
||||||
|
|
||||||
|
String serviceType = serviceType();
|
||||||
|
Constants.log.info("[DavService {}] Refreshing {} collections", service, serviceType);
|
||||||
|
|
||||||
|
// create authenticating OkHttpClient (credentials taken from account settings)
|
||||||
|
OkHttpClient httpClient = httpClient();
|
||||||
|
|
||||||
|
// refresh home sets
|
||||||
|
Set<HttpUrl> homeSets = readHomeSets();
|
||||||
|
HttpUrl principal = readPrincipal();
|
||||||
|
if (principal != null) {
|
||||||
|
Constants.log.debug("[DavService {}] Querying principal for home sets", service);
|
||||||
|
DavResource dav = new DavResource(null, httpClient, principal);
|
||||||
|
if (Services.SERVICE_CARDDAV.equals(serviceType)) {
|
||||||
|
dav.propfind(0, AddressbookHomeSet.NAME);
|
||||||
|
AddressbookHomeSet addressbookHomeSet = (AddressbookHomeSet)dav.properties.get(AddressbookHomeSet.NAME);
|
||||||
|
if (addressbookHomeSet != null)
|
||||||
|
for (String href : addressbookHomeSet.hrefs)
|
||||||
|
homeSets.add(UrlUtils.withTrailingSlash(dav.location.resolve(href)));
|
||||||
|
} else if (Services.SERVICE_CALDAV.equals(serviceType)) {
|
||||||
|
dav.propfind(0, CalendarHomeSet.NAME);
|
||||||
|
CalendarHomeSet calendarHomeSet = (CalendarHomeSet)dav.properties.get(CalendarHomeSet.NAME);
|
||||||
|
if (calendarHomeSet != null)
|
||||||
|
for (String href : calendarHomeSet.hrefs)
|
||||||
|
homeSets.add(UrlUtils.withTrailingSlash(dav.location.resolve(href)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
saveHomeSets(homeSets);
|
||||||
|
|
||||||
|
// refresh collections in home sets
|
||||||
|
Map<HttpUrl, CollectionInfo> collections = readCollections();
|
||||||
|
for (Iterator<HttpUrl> iterator = homeSets.iterator(); iterator.hasNext();) {
|
||||||
|
HttpUrl homeSet = iterator.next();
|
||||||
|
Constants.log.debug("[DavService {}] Listing home set {}", service, homeSet);
|
||||||
|
|
||||||
|
DavResource dav = new DavResource(null, httpClient, homeSet);
|
||||||
|
try {
|
||||||
|
dav.propfind(1, CollectionInfo.DAV_PROPERTIES);
|
||||||
|
for (DavResource member : dav.members) {
|
||||||
|
CollectionInfo info = CollectionInfo.fromDavResource(member);
|
||||||
|
info.confirmed = true;
|
||||||
|
Constants.log.debug("[DavService {}] Found collection {}", service, info);
|
||||||
|
|
||||||
|
if ((serviceType.equals(Services.SERVICE_CARDDAV) && info.type == CollectionInfo.Type.ADDRESS_BOOK) ||
|
||||||
|
(serviceType.equals(Services.SERVICE_CALDAV) && info.type == CollectionInfo.Type.CALENDAR))
|
||||||
|
collections.put(member.location, info);
|
||||||
|
}
|
||||||
|
} catch(NotFoundException e) {
|
||||||
|
// 404, remove home set
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check/refresh unconfirmed collections
|
||||||
|
for (Iterator<Map.Entry<HttpUrl, CollectionInfo>> iterator = collections.entrySet().iterator(); iterator.hasNext();) {
|
||||||
|
Map.Entry<HttpUrl, CollectionInfo> entry = iterator.next();
|
||||||
|
HttpUrl url = entry.getKey();
|
||||||
|
CollectionInfo info = entry.getValue();
|
||||||
|
|
||||||
|
if (!info.confirmed)
|
||||||
|
try {
|
||||||
|
DavResource dav = new DavResource(null, httpClient, url);
|
||||||
|
dav.propfind(0, CollectionInfo.DAV_PROPERTIES);
|
||||||
|
info = CollectionInfo.fromDavResource(dav);
|
||||||
|
info.confirmed = true;
|
||||||
|
|
||||||
|
// remove unusable collections
|
||||||
|
if ((serviceType.equals(Services.SERVICE_CARDDAV) && info.type != CollectionInfo.Type.ADDRESS_BOOK) ||
|
||||||
|
(serviceType.equals(Services.SERVICE_CALDAV) && info.type != CollectionInfo.Type.CALENDAR))
|
||||||
|
iterator.remove();
|
||||||
|
} catch(NotFoundException e) {
|
||||||
|
// 404, remove collection
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
saveCollections(collections.values());
|
||||||
|
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
} catch (SQLiteException | IOException|HttpException|DavException e) {
|
||||||
|
Constants.log.error("Couldn't refresh collection list", e);
|
||||||
} finally {
|
} finally {
|
||||||
Constants.log.debug("RefreshCollections.Runner FINISHED {}", serviceId);
|
db.endTransaction();
|
||||||
runningRefresh.remove(serviceId);
|
dbHelper.close();
|
||||||
|
|
||||||
|
runningRefresh.remove(service);
|
||||||
for (RefreshingStatusListener listener : refreshingStatusListeners)
|
for (RefreshingStatusListener listener : refreshingStatusListeners)
|
||||||
listener.onDavRefreshStatusChanged(serviceId, false);
|
listener.onDavRefreshStatusChanged(service, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String serviceType() {
|
||||||
|
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[]{Services.SERVICE}, Services.ID + "=?", new String[]{String.valueOf(service)}, null, null, null);
|
||||||
|
if (cursor.moveToNext())
|
||||||
|
return cursor.getString(0);
|
||||||
|
else
|
||||||
|
throw new IllegalArgumentException("Service not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
private OkHttpClient httpClient() {
|
||||||
|
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[]{Services.ACCOUNT_NAME}, Services.ID + "=?", new String[]{String.valueOf(service)}, null, null, null);
|
||||||
|
if (cursor.moveToNext()) {
|
||||||
|
Account account = new Account(cursor.getString(0), Constants.ACCOUNT_TYPE);
|
||||||
|
AccountSettings settings = new AccountSettings(DavService.this, account);
|
||||||
|
|
||||||
|
OkHttpClient httpClient = HttpClient.create(DavService.this);
|
||||||
|
httpClient = HttpClient.addAuthentication(httpClient, settings.username(), settings.password(), settings.preemptiveAuth());
|
||||||
|
return httpClient;
|
||||||
|
} else
|
||||||
|
throw new IllegalArgumentException("Service not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpUrl readPrincipal() {
|
||||||
|
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[]{Services.PRINCIPAL}, Services.ID + "=?", new String[]{String.valueOf(service)}, null, null, null);
|
||||||
|
if (cursor.moveToNext()) {
|
||||||
|
String principal = cursor.getString(0);
|
||||||
|
if (principal != null)
|
||||||
|
return HttpUrl.parse(cursor.getString(0));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<HttpUrl> readHomeSets() {
|
||||||
|
Set<HttpUrl> homeSets = new LinkedHashSet<>();
|
||||||
|
@Cleanup Cursor cursor = db.query(HomeSets._TABLE, new String[]{HomeSets.URL}, HomeSets.SERVICE_ID + "=?", new String[]{String.valueOf(service)}, null, null, null);
|
||||||
|
while (cursor.moveToNext())
|
||||||
|
homeSets.add(HttpUrl.parse(cursor.getString(0)));
|
||||||
|
return homeSets;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveHomeSets(Set<HttpUrl> homeSets) {
|
||||||
|
db.delete(HomeSets._TABLE, HomeSets.SERVICE_ID + "=?", new String[]{String.valueOf(service)});
|
||||||
|
for (HttpUrl homeSet : homeSets) {
|
||||||
|
ContentValues values = new ContentValues(1);
|
||||||
|
values.put(HomeSets.SERVICE_ID, service);
|
||||||
|
values.put(HomeSets.URL, homeSet.toString());
|
||||||
|
db.insertOrThrow(HomeSets._TABLE, null, values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<HttpUrl, CollectionInfo> readCollections() {
|
||||||
|
Map<HttpUrl, CollectionInfo> collections = new LinkedHashMap<>();
|
||||||
|
@Cleanup Cursor cursor = db.query(Collections._TABLE, Collections._COLUMNS, Collections.SERVICE_ID + "=?", new String[]{String.valueOf(service)}, null, null, null);
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
DatabaseUtils.cursorRowToContentValues(cursor, values);
|
||||||
|
collections.put(HttpUrl.parse(values.getAsString(Collections.URL)), CollectionInfo.fromDB(values));
|
||||||
|
}
|
||||||
|
return collections;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveCollections(Iterable<CollectionInfo> collections) {
|
||||||
|
db.delete(Collections._TABLE, HomeSets.SERVICE_ID + "=?", new String[]{String.valueOf(service)});
|
||||||
|
for (CollectionInfo collection : collections) {
|
||||||
|
ContentValues values = collection.toDB();
|
||||||
|
Constants.log.debug("Saving collection: {}", values);
|
||||||
|
values.put(Collections.SERVICE_ID, service);
|
||||||
|
db.insertWithOnConflict(Collections._TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,11 @@
|
|||||||
|
|
||||||
package at.bitfire.davdroid;
|
package at.bitfire.davdroid;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import at.bitfire.davdroid.resource.DavResourceFinder;
|
|
||||||
import okhttp3.Cookie;
|
import okhttp3.Cookie;
|
||||||
import okhttp3.CookieJar;
|
import okhttp3.CookieJar;
|
||||||
import okhttp3.HttpUrl;
|
import okhttp3.HttpUrl;
|
||||||
|
127
app/src/main/java/at/bitfire/davdroid/model/CollectionInfo.java
Normal file
127
app/src/main/java/at/bitfire/davdroid/model/CollectionInfo.java
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2013 – 2016 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.model;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
|
||||||
|
import at.bitfire.dav4android.DavResource;
|
||||||
|
import at.bitfire.dav4android.Property;
|
||||||
|
import at.bitfire.dav4android.property.AddressbookDescription;
|
||||||
|
import at.bitfire.dav4android.property.CalendarColor;
|
||||||
|
import at.bitfire.dav4android.property.CalendarDescription;
|
||||||
|
import at.bitfire.dav4android.property.CurrentUserPrivilegeSet;
|
||||||
|
import at.bitfire.dav4android.property.DisplayName;
|
||||||
|
import at.bitfire.dav4android.property.ResourceType;
|
||||||
|
import at.bitfire.dav4android.property.SupportedCalendarComponentSet;
|
||||||
|
import lombok.ToString;
|
||||||
|
import okhttp3.HttpUrl;
|
||||||
|
import at.bitfire.davdroid.model.ServiceDB.*;
|
||||||
|
|
||||||
|
@ToString
|
||||||
|
public class CollectionInfo {
|
||||||
|
public long id;
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
ADDRESS_BOOK,
|
||||||
|
CALENDAR
|
||||||
|
};
|
||||||
|
public Type type;
|
||||||
|
|
||||||
|
public String url;
|
||||||
|
|
||||||
|
public boolean readOnly;
|
||||||
|
public String displayName, description;
|
||||||
|
public Integer color;
|
||||||
|
|
||||||
|
public Boolean supportsVEVENT;
|
||||||
|
public Boolean supportsVTODO;
|
||||||
|
|
||||||
|
// non-persistent properties
|
||||||
|
public boolean confirmed;
|
||||||
|
|
||||||
|
|
||||||
|
public static final Property.Name[] DAV_PROPERTIES = {
|
||||||
|
ResourceType.NAME,
|
||||||
|
CurrentUserPrivilegeSet.NAME,
|
||||||
|
DisplayName.NAME,
|
||||||
|
AddressbookDescription.NAME, CalendarDescription.NAME,
|
||||||
|
CalendarColor.NAME, SupportedCalendarComponentSet.NAME
|
||||||
|
};
|
||||||
|
|
||||||
|
public static CollectionInfo fromDavResource(DavResource dav) {
|
||||||
|
CollectionInfo info = new CollectionInfo();
|
||||||
|
info.url = dav.location.toString();
|
||||||
|
|
||||||
|
ResourceType type = (ResourceType)dav.properties.get(ResourceType.NAME);
|
||||||
|
if (type != null) {
|
||||||
|
if (type.types.contains(ResourceType.ADDRESSBOOK))
|
||||||
|
info.type = Type.ADDRESS_BOOK;
|
||||||
|
else if (type.types.contains(ResourceType.CALENDAR))
|
||||||
|
info.type = Type.CALENDAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean readOnly = false;
|
||||||
|
CurrentUserPrivilegeSet privilegeSet = (CurrentUserPrivilegeSet)dav.properties.get(CurrentUserPrivilegeSet.NAME);
|
||||||
|
if (privilegeSet != null)
|
||||||
|
readOnly = !privilegeSet.mayWriteContent;
|
||||||
|
|
||||||
|
DisplayName displayName = (DisplayName)dav.properties.get(DisplayName.NAME);
|
||||||
|
if (displayName != null && !displayName.displayName.isEmpty())
|
||||||
|
info.displayName = displayName.displayName;
|
||||||
|
|
||||||
|
if (info.type == Type.ADDRESS_BOOK) {
|
||||||
|
AddressbookDescription addressbookDescription = (AddressbookDescription)dav.properties.get(AddressbookDescription.NAME);
|
||||||
|
if (addressbookDescription != null)
|
||||||
|
info.description = addressbookDescription.description;
|
||||||
|
|
||||||
|
} else if (info.type == Type.CALENDAR) {
|
||||||
|
CalendarDescription calendarDescription = (CalendarDescription)dav.properties.get(CalendarDescription.NAME);
|
||||||
|
if (calendarDescription != null)
|
||||||
|
info.description = calendarDescription.description;
|
||||||
|
|
||||||
|
CalendarColor calendarColor = (CalendarColor)dav.properties.get(CalendarColor.NAME);
|
||||||
|
if (calendarColor != null)
|
||||||
|
info.color = calendarColor.color;
|
||||||
|
|
||||||
|
info.supportsVEVENT = info.supportsVTODO = true;
|
||||||
|
SupportedCalendarComponentSet supportedCalendarComponentSet = (SupportedCalendarComponentSet)dav.properties.get(SupportedCalendarComponentSet.NAME);
|
||||||
|
if (supportedCalendarComponentSet != null) {
|
||||||
|
info.supportsVEVENT = supportedCalendarComponentSet.supportsEvents;
|
||||||
|
info.supportsVTODO = supportedCalendarComponentSet.supportsTasks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static CollectionInfo fromDB(ContentValues values) {
|
||||||
|
CollectionInfo info = new CollectionInfo();
|
||||||
|
info.id = values.getAsLong(Collections.ID);
|
||||||
|
info.url = values.getAsString(Collections.URL);
|
||||||
|
info.displayName = values.getAsString(Collections.DISPLAY_NAME);
|
||||||
|
info.description = values.getAsString(Collections.DESCRIPTION);
|
||||||
|
info.color = values.getAsInteger(Collections.COLOR);
|
||||||
|
info.supportsVEVENT = values.getAsBoolean(Collections.SUPPORTS_VEVENT);
|
||||||
|
info.supportsVTODO = values.getAsBoolean(Collections.SUPPORTS_VTODO);
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentValues toDB() {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(Collections.URL, url);
|
||||||
|
values.put(Collections.DISPLAY_NAME, displayName);
|
||||||
|
values.put(Collections.DESCRIPTION, description);
|
||||||
|
values.put(Collections.COLOR, color);
|
||||||
|
values.put(Collections.SUPPORTS_VEVENT, supportsVEVENT);
|
||||||
|
values.put(Collections.SUPPORTS_VTODO, supportsVTODO);
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,15 +6,16 @@
|
|||||||
* http://www.gnu.org/licenses/gpl.html
|
* http://www.gnu.org/licenses/gpl.html
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package at.bitfire.davdroid.syncadapter;
|
package at.bitfire.davdroid.model;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
import at.bitfire.davdroid.Constants;
|
import at.bitfire.davdroid.Constants;
|
||||||
import at.bitfire.davdroid.resource.DavResourceFinder;
|
import at.bitfire.davdroid.ui.setup.DavResourceFinder;
|
||||||
|
|
||||||
public class ServiceDB {
|
public class ServiceDB {
|
||||||
|
|
||||||
@ -22,10 +23,10 @@ public class ServiceDB {
|
|||||||
public static final String
|
public static final String
|
||||||
_TABLE = "services",
|
_TABLE = "services",
|
||||||
ID = "_id",
|
ID = "_id",
|
||||||
ACCOUNT_NAME = "account_name",
|
ACCOUNT_NAME = "accountName",
|
||||||
SERVICE = "service",
|
SERVICE = "service",
|
||||||
PRINCIPAL = "principal",
|
PRINCIPAL = "principal",
|
||||||
LAST_REFRESH = "last_refresh";
|
LAST_REFRESH = "lastRefresh";
|
||||||
|
|
||||||
// allowed values for SERVICE column
|
// allowed values for SERVICE column
|
||||||
public static final String
|
public static final String
|
||||||
@ -37,7 +38,7 @@ public class ServiceDB {
|
|||||||
public static final String
|
public static final String
|
||||||
_TABLE = "homesets",
|
_TABLE = "homesets",
|
||||||
ID = "_id",
|
ID = "_id",
|
||||||
SERVICE_ID = "service_id",
|
SERVICE_ID = "serviceID",
|
||||||
URL = "url";
|
URL = "url";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,17 +46,17 @@ public class ServiceDB {
|
|||||||
public static final String
|
public static final String
|
||||||
_TABLE = "collections",
|
_TABLE = "collections",
|
||||||
ID = "_id",
|
ID = "_id",
|
||||||
SERVICE_ID = "service_id",
|
SERVICE_ID = "serviceID",
|
||||||
URL = "url",
|
URL = "url",
|
||||||
DISPLAY_NAME = "display_name",
|
DISPLAY_NAME = "displayName",
|
||||||
DESCRIPTION = "description";
|
DESCRIPTION = "description",
|
||||||
|
COLOR = "color",
|
||||||
|
SUPPORTS_VEVENT = "supportsVEVENT",
|
||||||
|
SUPPORTS_VTODO = "supportsVTODO";
|
||||||
|
|
||||||
public static ContentValues fromCollection(DavResourceFinder.Configuration.Collection collection) {
|
public static String[] _COLUMNS = new String[] {
|
||||||
ContentValues values = new ContentValues();
|
ID, SERVICE_ID, URL, DISPLAY_NAME, DESCRIPTION, COLOR, SUPPORTS_VEVENT, SUPPORTS_VTODO
|
||||||
values.put(DISPLAY_NAME, collection.getDisplayName());
|
};
|
||||||
values.put(DESCRIPTION, collection.getDescription());
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -67,6 +68,14 @@ public class ServiceDB {
|
|||||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOpen(SQLiteDatabase db) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
|
||||||
|
db.setForeignKeyConstraintsEnabled(true);
|
||||||
|
else
|
||||||
|
db.execSQL("PRAGMA foreign_keys=ON;");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(SQLiteDatabase db) {
|
public void onCreate(SQLiteDatabase db) {
|
||||||
Constants.log.info("Creating services database");
|
Constants.log.info("Creating services database");
|
||||||
@ -78,20 +87,26 @@ public class ServiceDB {
|
|||||||
Services.PRINCIPAL + " TEXT NULL, " +
|
Services.PRINCIPAL + " TEXT NULL, " +
|
||||||
Services.LAST_REFRESH + " INTEGER NULL" +
|
Services.LAST_REFRESH + " INTEGER NULL" +
|
||||||
")");
|
")");
|
||||||
|
db.execSQL("CREATE UNIQUE INDEX services_account ON " + Services._TABLE + " (" + Services.ACCOUNT_NAME + "," + Services.SERVICE + ")");
|
||||||
|
|
||||||
db.execSQL("CREATE TABLE " + HomeSets._TABLE + "(" +
|
db.execSQL("CREATE TABLE " + HomeSets._TABLE + "(" +
|
||||||
HomeSets.ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
|
HomeSets.ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
|
||||||
HomeSets.SERVICE_ID + " INTEGER NOT NULL," +
|
HomeSets.SERVICE_ID + " INTEGER NOT NULL REFERENCES " + Services._TABLE +" ON DELETE CASCADE," +
|
||||||
HomeSets.URL + " TEXT NOT NULL" +
|
HomeSets.URL + " TEXT NOT NULL" +
|
||||||
")");
|
")");
|
||||||
|
db.execSQL("CREATE UNIQUE INDEX homesets_service_url ON " + HomeSets._TABLE + "(" + HomeSets.SERVICE_ID + "," + HomeSets.URL + ")");
|
||||||
|
|
||||||
db.execSQL("CREATE TABLE " + Collections._TABLE + "(" +
|
db.execSQL("CREATE TABLE " + Collections._TABLE + "(" +
|
||||||
Collections.ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
|
Collections.ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
|
||||||
Collections.SERVICE_ID + " INTEGER NOT NULL," +
|
Collections.SERVICE_ID + " INTEGER NOT NULL REFERENCES " + Services._TABLE +" ON DELETE CASCADE," +
|
||||||
Collections.URL + " TEXT NOT NULL," +
|
Collections.URL + " TEXT NOT NULL," +
|
||||||
Collections.DISPLAY_NAME + " TEXT NULL," +
|
Collections.DISPLAY_NAME + " TEXT NULL," +
|
||||||
Collections.DESCRIPTION + " TEXT NULL" +
|
Collections.DESCRIPTION + " TEXT NULL," +
|
||||||
|
Collections.COLOR + " INTEGER NULL," +
|
||||||
|
Collections.SUPPORTS_VEVENT + " INTEGER NULL," +
|
||||||
|
Collections.SUPPORTS_VTODO + " INTEGER NULL" +
|
||||||
")");
|
")");
|
||||||
|
db.execSQL("CREATE UNIQUE INDEX collections_service_url ON " + Collections._TABLE + "(" + Collections.SERVICE_ID + "," + Collections.URL + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
@ -15,36 +15,42 @@ import android.accounts.AccountManagerFuture;
|
|||||||
import android.accounts.AuthenticatorException;
|
import android.accounts.AuthenticatorException;
|
||||||
import android.accounts.OperationCanceledException;
|
import android.accounts.OperationCanceledException;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
|
||||||
import android.app.LoaderManager;
|
import android.app.LoaderManager;
|
||||||
import android.content.AsyncTaskLoader;
|
import android.content.AsyncTaskLoader;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.Loader;
|
import android.content.Loader;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.database.DatabaseUtils;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.support.v4.app.DialogFragment;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.support.v7.widget.CardView;
|
import android.support.v7.widget.CardView;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.ListView;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import at.bitfire.davdroid.Constants;
|
import at.bitfire.davdroid.Constants;
|
||||||
import at.bitfire.davdroid.R;
|
|
||||||
import at.bitfire.davdroid.DavService;
|
import at.bitfire.davdroid.DavService;
|
||||||
import at.bitfire.davdroid.syncadapter.ServiceDB.*;
|
import at.bitfire.davdroid.R;
|
||||||
|
import at.bitfire.davdroid.model.CollectionInfo;
|
||||||
|
import at.bitfire.davdroid.model.ServiceDB.Collections;
|
||||||
|
import at.bitfire.davdroid.model.ServiceDB.OpenHelper;
|
||||||
|
import at.bitfire.davdroid.model.ServiceDB.Services;
|
||||||
import lombok.Cleanup;
|
import lombok.Cleanup;
|
||||||
|
|
||||||
public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenuItemClickListener, ServiceConnection, DavService.RefreshingStatusListener, LoaderManager.LoaderCallbacks<AccountActivity.AccountInfo> {
|
public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenuItemClickListener, ServiceConnection, DavService.RefreshingStatusListener, LoaderManager.LoaderCallbacks<AccountActivity.AccountInfo> {
|
||||||
@ -59,7 +65,7 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
final String accountName = getIntent().getStringExtra(EXTRA_ACCOUNT_NAME);
|
accountName = getIntent().getStringExtra(EXTRA_ACCOUNT_NAME);
|
||||||
if (accountName == null)
|
if (accountName == null)
|
||||||
// invalid account name
|
// invalid account name
|
||||||
finish();
|
finish();
|
||||||
@ -125,13 +131,13 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
case R.id.refresh_address_books:
|
case R.id.refresh_address_books:
|
||||||
Intent intent = new Intent(this, DavService.class);
|
Intent intent = new Intent(this, DavService.class);
|
||||||
intent.setAction(DavService.ACTION_REFRESH_COLLECTIONS);
|
intent.setAction(DavService.ACTION_REFRESH_COLLECTIONS);
|
||||||
intent.putExtra(DavService.EXTRA_DAV_SERVICE_ID, accountInfo.cardDavService);
|
intent.putExtra(DavService.EXTRA_DAV_SERVICE_ID, accountInfo.carddav.id);
|
||||||
startService(intent);
|
startService(intent);
|
||||||
break;
|
break;
|
||||||
case R.id.refresh_calendars:
|
case R.id.refresh_calendars:
|
||||||
intent = new Intent(this, DavService.class);
|
intent = new Intent(this, DavService.class);
|
||||||
intent.setAction(DavService.ACTION_REFRESH_COLLECTIONS);
|
intent.setAction(DavService.ACTION_REFRESH_COLLECTIONS);
|
||||||
intent.putExtra(DavService.EXTRA_DAV_SERVICE_ID, accountInfo.calDavService);
|
intent.putExtra(DavService.EXTRA_DAV_SERVICE_ID, accountInfo.caldav.id);
|
||||||
startService(intent);
|
startService(intent);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -162,11 +168,14 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
/* LOADERS AND LOADED DATA */
|
/* LOADERS AND LOADED DATA */
|
||||||
|
|
||||||
public static class AccountInfo {
|
public static class AccountInfo {
|
||||||
Long cardDavService;
|
ServiceInfo carddav, caldav;
|
||||||
boolean cardDavRefreshing;
|
|
||||||
|
|
||||||
Long calDavService;
|
public static class ServiceInfo {
|
||||||
boolean calDavRefreshing;
|
long id;
|
||||||
|
boolean refreshing;
|
||||||
|
|
||||||
|
List<CollectionInfo> collections;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -179,16 +188,28 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
accountInfo = info;
|
accountInfo = info;
|
||||||
|
|
||||||
CardView card = (CardView)findViewById(R.id.carddav);
|
CardView card = (CardView)findViewById(R.id.carddav);
|
||||||
if (info.cardDavService != null) {
|
if (info.carddav != null) {
|
||||||
ProgressBar progress = (ProgressBar)findViewById(R.id.carddav_refreshing);
|
ProgressBar progress = (ProgressBar)findViewById(R.id.carddav_refreshing);
|
||||||
progress.setVisibility(info.cardDavRefreshing ? View.VISIBLE : View.GONE);
|
progress.setVisibility(info.carddav.refreshing ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
|
ListView list = (ListView)findViewById(R.id.address_books);
|
||||||
|
List<String> names = new LinkedList<>();
|
||||||
|
for (CollectionInfo addrBook : info.carddav.collections)
|
||||||
|
names.add(addrBook.displayName != null ? addrBook.displayName : addrBook.url);
|
||||||
|
list.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_checked, android.R.id.text1, names));
|
||||||
} else
|
} else
|
||||||
card.setVisibility(View.GONE);
|
card.setVisibility(View.GONE);
|
||||||
|
|
||||||
card = (CardView)findViewById(R.id.caldav);
|
card = (CardView)findViewById(R.id.caldav);
|
||||||
if (info.calDavService != null) {
|
if (info.caldav != null) {
|
||||||
ProgressBar progress = (ProgressBar)findViewById(R.id.caldav_refreshing);
|
ProgressBar progress = (ProgressBar)findViewById(R.id.caldav_refreshing);
|
||||||
progress.setVisibility(info.calDavRefreshing ? View.VISIBLE : View.GONE);
|
progress.setVisibility(info.caldav.refreshing ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
|
ListView list = (ListView)findViewById(R.id.calendars);
|
||||||
|
List<String> names = new LinkedList<>();
|
||||||
|
for (CollectionInfo calendar : info.caldav.collections)
|
||||||
|
names.add(calendar.displayName != null ? calendar.displayName : calendar.url);
|
||||||
|
list.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_checked, android.R.id.text1, names));
|
||||||
} else
|
} else
|
||||||
card.setVisibility(View.GONE);
|
card.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
@ -251,11 +272,16 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
|
|
||||||
String service = cursor.getString(1);
|
String service = cursor.getString(1);
|
||||||
if (Services.SERVICE_CARDDAV.equals(service)) {
|
if (Services.SERVICE_CARDDAV.equals(service)) {
|
||||||
info.cardDavService = id;
|
info.carddav = new AccountInfo.ServiceInfo();
|
||||||
info.cardDavRefreshing = davService.isRefreshing(id);
|
info.carddav.id = id;
|
||||||
|
info.carddav.refreshing = davService.isRefreshing(id);
|
||||||
|
info.carddav.collections = readCollections(db, id);
|
||||||
|
|
||||||
} else if (Services.SERVICE_CALDAV.equals(service)) {
|
} else if (Services.SERVICE_CALDAV.equals(service)) {
|
||||||
info.calDavService = id;
|
info.caldav = new AccountInfo.ServiceInfo();
|
||||||
info.calDavRefreshing = davService.isRefreshing(id);
|
info.caldav.id = id;
|
||||||
|
info.caldav.refreshing = davService.isRefreshing(id);
|
||||||
|
info.caldav.collections = readCollections(db, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -263,6 +289,17 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
}
|
}
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<CollectionInfo> readCollections(SQLiteDatabase db, long service) {
|
||||||
|
List<CollectionInfo> collections = new LinkedList<>();
|
||||||
|
@Cleanup Cursor cursor = db.query(Collections._TABLE, Collections._COLUMNS, Collections.SERVICE_ID + "=?", new String[]{String.valueOf(service)}, null, null, null);
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
DatabaseUtils.cursorRowToContentValues(cursor, values);
|
||||||
|
collections.add(CollectionInfo.fromDB(values));
|
||||||
|
}
|
||||||
|
return collections;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,14 +11,11 @@ package at.bitfire.davdroid.ui;
|
|||||||
import android.accounts.Account;
|
import android.accounts.Account;
|
||||||
import android.accounts.AccountManager;
|
import android.accounts.AccountManager;
|
||||||
import android.accounts.OnAccountsUpdateListener;
|
import android.accounts.OnAccountsUpdateListener;
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
|
||||||
import android.support.v4.app.ListFragment;
|
import android.support.v4.app.ListFragment;
|
||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.AsyncTaskLoader;
|
import android.support.v4.content.AsyncTaskLoader;
|
||||||
@ -41,8 +38,8 @@ import java.util.List;
|
|||||||
import at.bitfire.davdroid.Constants;
|
import at.bitfire.davdroid.Constants;
|
||||||
import at.bitfire.davdroid.DavService;
|
import at.bitfire.davdroid.DavService;
|
||||||
import at.bitfire.davdroid.R;
|
import at.bitfire.davdroid.R;
|
||||||
import at.bitfire.davdroid.syncadapter.ServiceDB.OpenHelper;
|
import at.bitfire.davdroid.model.ServiceDB.OpenHelper;
|
||||||
import at.bitfire.davdroid.syncadapter.ServiceDB.Services;
|
import at.bitfire.davdroid.model.ServiceDB.Services;
|
||||||
import lombok.Cleanup;
|
import lombok.Cleanup;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ package at.bitfire.davdroid.ui.setup;
|
|||||||
import android.accounts.Account;
|
import android.accounts.Account;
|
||||||
import android.accounts.AccountManager;
|
import android.accounts.AccountManager;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
|
import android.content.Intent;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
@ -24,10 +25,11 @@ import android.widget.EditText;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import at.bitfire.davdroid.Constants;
|
import at.bitfire.davdroid.Constants;
|
||||||
|
import at.bitfire.davdroid.DavService;
|
||||||
import at.bitfire.davdroid.R;
|
import at.bitfire.davdroid.R;
|
||||||
import at.bitfire.davdroid.resource.DavResourceFinder;
|
import at.bitfire.davdroid.model.CollectionInfo;
|
||||||
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
||||||
import at.bitfire.davdroid.syncadapter.ServiceDB.*;
|
import at.bitfire.davdroid.model.ServiceDB.*;
|
||||||
import lombok.Cleanup;
|
import lombok.Cleanup;
|
||||||
import okhttp3.HttpUrl;
|
import okhttp3.HttpUrl;
|
||||||
|
|
||||||
@ -56,7 +58,11 @@ public class AccountDetailsFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
DavResourceFinder.Configuration config = (DavResourceFinder.Configuration)getArguments().getSerializable(KEY_CONFIG);
|
||||||
|
|
||||||
final EditText editName = (EditText)v.findViewById(R.id.account_name);
|
final EditText editName = (EditText)v.findViewById(R.id.account_name);
|
||||||
|
editName.setText(config.userName);
|
||||||
|
|
||||||
Button btnCreate = (Button)v.findViewById(R.id.create_account);
|
Button btnCreate = (Button)v.findViewById(R.id.create_account);
|
||||||
btnCreate.setOnClickListener(new View.OnClickListener() {
|
btnCreate.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -92,11 +98,20 @@ public class AccountDetailsFragment extends Fragment {
|
|||||||
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
||||||
db.beginTransactionNonExclusive();
|
db.beginTransactionNonExclusive();
|
||||||
try {
|
try {
|
||||||
if (config.cardDAV != null)
|
Intent refreshIntent = new Intent(getActivity(), DavService.class);
|
||||||
insertService(db, accountName, Services.SERVICE_CARDDAV, config.cardDAV);
|
refreshIntent.setAction(DavService.ACTION_REFRESH_COLLECTIONS);
|
||||||
|
|
||||||
if (config.calDAV != null)
|
if (config.cardDAV != null) {
|
||||||
insertService(db, accountName, Services.SERVICE_CALDAV, config.calDAV);
|
long id = insertService(db, accountName, Services.SERVICE_CARDDAV, config.cardDAV);
|
||||||
|
refreshIntent.putExtra(DavService.EXTRA_DAV_SERVICE_ID, id);
|
||||||
|
getActivity().startService(refreshIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.calDAV != null) {
|
||||||
|
long id = insertService(db, accountName, Services.SERVICE_CALDAV, config.calDAV);
|
||||||
|
refreshIntent.putExtra(DavService.EXTRA_DAV_SERVICE_ID, id);
|
||||||
|
getActivity().startService(refreshIntent);
|
||||||
|
}
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
@ -106,7 +121,7 @@ public class AccountDetailsFragment extends Fragment {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void insertService(SQLiteDatabase db, String accountName, String service, DavResourceFinder.Configuration.ServiceInfo info) {
|
protected long insertService(SQLiteDatabase db, String accountName, String service, DavResourceFinder.Configuration.ServiceInfo info) {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
|
|
||||||
// insert service
|
// insert service
|
||||||
@ -125,12 +140,13 @@ public class AccountDetailsFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// insert collections
|
// insert collections
|
||||||
for (Map.Entry<HttpUrl, DavResourceFinder.Configuration.Collection> entry : info.getCollections().entrySet()) {
|
for (CollectionInfo collection : info.getCollections().values()) {
|
||||||
values = Collections.fromCollection(entry.getValue());
|
values = collection.toDB();
|
||||||
values.put(Collections.SERVICE_ID, serviceID);
|
values.put(Collections.SERVICE_ID, serviceID);
|
||||||
values.put(Collections.URL, entry.getKey().toString());
|
|
||||||
db.insertOrThrow(Collections._TABLE, null, values);
|
db.insertOrThrow(Collections._TABLE, null, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return serviceID;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
* http://www.gnu.org/licenses/gpl.html
|
* http://www.gnu.org/licenses/gpl.html
|
||||||
*/
|
*/
|
||||||
package at.bitfire.davdroid.resource;
|
package at.bitfire.davdroid.ui.setup;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@ -45,7 +45,7 @@ import at.bitfire.dav4android.property.ResourceType;
|
|||||||
import at.bitfire.dav4android.property.SupportedCalendarComponentSet;
|
import at.bitfire.dav4android.property.SupportedCalendarComponentSet;
|
||||||
import at.bitfire.davdroid.HttpClient;
|
import at.bitfire.davdroid.HttpClient;
|
||||||
import at.bitfire.davdroid.log.StringLogger;
|
import at.bitfire.davdroid.log.StringLogger;
|
||||||
import at.bitfire.davdroid.ui.setup.LoginCredentialsFragment;
|
import at.bitfire.davdroid.model.CollectionInfo;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
@ -194,14 +194,14 @@ public class DavResourceFinder {
|
|||||||
if (resourceType != null && resourceType.types.contains(ResourceType.ADDRESSBOOK)) {
|
if (resourceType != null && resourceType.types.contains(ResourceType.ADDRESSBOOK)) {
|
||||||
dav.location = UrlUtils.withTrailingSlash(dav.location);
|
dav.location = UrlUtils.withTrailingSlash(dav.location);
|
||||||
log.info("Found address book at " + dav.location);
|
log.info("Found address book at " + dav.location);
|
||||||
config.collections.put(dav.location, collectionInfo(dav, Configuration.Collection.Type.ADDRESS_BOOK));
|
config.collections.put(dav.location, CollectionInfo.fromDavResource(dav));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does the collection refer to address book homesets?
|
// Does the collection refer to address book homesets?
|
||||||
AddressbookHomeSet homeSets = (AddressbookHomeSet)dav.properties.get(AddressbookHomeSet.NAME);
|
AddressbookHomeSet homeSets = (AddressbookHomeSet)dav.properties.get(AddressbookHomeSet.NAME);
|
||||||
if (homeSets != null)
|
if (homeSets != null)
|
||||||
for (String href : homeSets.hrefs)
|
for (String href : homeSets.hrefs)
|
||||||
config.homeSets.add(dav.location.resolve(href));
|
config.homeSets.add(UrlUtils.withTrailingSlash(dav.location.resolve(href)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void rememberIfCalendarOrHomeset(@NonNull DavResource dav, @NonNull Configuration.ServiceInfo config) {
|
protected void rememberIfCalendarOrHomeset(@NonNull DavResource dav, @NonNull Configuration.ServiceInfo config) {
|
||||||
@ -210,77 +210,14 @@ public class DavResourceFinder {
|
|||||||
if (resourceType != null && resourceType.types.contains(ResourceType.CALENDAR)) {
|
if (resourceType != null && resourceType.types.contains(ResourceType.CALENDAR)) {
|
||||||
dav.location = UrlUtils.withTrailingSlash(dav.location);
|
dav.location = UrlUtils.withTrailingSlash(dav.location);
|
||||||
log.info("Found calendar collection at " + dav.location);
|
log.info("Found calendar collection at " + dav.location);
|
||||||
|
config.collections.put(dav.location, CollectionInfo.fromDavResource(dav));
|
||||||
boolean supportsEvents = true, supportsTasks = true;
|
|
||||||
SupportedCalendarComponentSet supportedCalendarComponentSet = (SupportedCalendarComponentSet)dav.properties.get(SupportedCalendarComponentSet.NAME);
|
|
||||||
if (supportedCalendarComponentSet != null) {
|
|
||||||
supportsEvents = supportedCalendarComponentSet.supportsEvents;
|
|
||||||
supportsTasks = supportedCalendarComponentSet.supportsTasks;
|
|
||||||
}
|
|
||||||
if (supportsEvents || supportsTasks) {
|
|
||||||
Configuration.Collection info = collectionInfo(dav, Configuration.Collection.Type.CALENDAR);
|
|
||||||
info.supportsEvents = supportsEvents;
|
|
||||||
info.supportsTasks = supportsTasks;
|
|
||||||
config.collections.put(dav.location, info);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does the collection refer to calendar homesets?
|
// Does the collection refer to calendar homesets?
|
||||||
CalendarHomeSet homeSets = (CalendarHomeSet)dav.properties.get(CalendarHomeSet.NAME);
|
CalendarHomeSet homeSets = (CalendarHomeSet)dav.properties.get(CalendarHomeSet.NAME);
|
||||||
if (homeSets != null)
|
if (homeSets != null)
|
||||||
for (String href : homeSets.hrefs)
|
for (String href : homeSets.hrefs)
|
||||||
config.homeSets.add(dav.location.resolve(href));
|
config.homeSets.add(UrlUtils.withTrailingSlash(dav.location.resolve(href)));
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a #{@link at.bitfire.davdroid.resource.DavResourceFinder.Configuration.Collection} from a given
|
|
||||||
* #{@link DavResource}. Uses these DAV properties:
|
|
||||||
* <ul>
|
|
||||||
* <li>calendars: current-user-properties, current-user-privilege-set, displayname, calendar-description, calendar-color</li>
|
|
||||||
* <li>address books: current-user-properties, current-user-privilege-set, displayname, addressbook-description</li>
|
|
||||||
* </ul>. Make sure you have queried these properties from the DavResource.
|
|
||||||
* @param dav DavResource to take the resource info from
|
|
||||||
* @param type must be ADDRESS_BOOK or CALENDAR
|
|
||||||
* @return ResourceInfo which represents the DavResource
|
|
||||||
*/
|
|
||||||
protected Configuration.Collection collectionInfo(DavResource dav, Configuration.Collection.Type type) {
|
|
||||||
boolean readOnly = false;
|
|
||||||
CurrentUserPrivilegeSet privilegeSet = (CurrentUserPrivilegeSet)dav.properties.get(CurrentUserPrivilegeSet.NAME);
|
|
||||||
if (privilegeSet != null)
|
|
||||||
readOnly = !privilegeSet.mayWriteContent;
|
|
||||||
|
|
||||||
String title = null;
|
|
||||||
DisplayName displayName = (DisplayName)dav.properties.get(DisplayName.NAME);
|
|
||||||
if (displayName != null)
|
|
||||||
title = displayName.displayName;
|
|
||||||
if (TextUtils.isEmpty(title))
|
|
||||||
title = UrlUtils.lastSegment(dav.location);
|
|
||||||
|
|
||||||
String description = null;
|
|
||||||
Integer color = null;
|
|
||||||
if (type == Configuration.Collection.Type.ADDRESS_BOOK) {
|
|
||||||
AddressbookDescription addressbookDescription = (AddressbookDescription)dav.properties.get(AddressbookDescription.NAME);
|
|
||||||
if (addressbookDescription != null)
|
|
||||||
description = addressbookDescription.description;
|
|
||||||
} else if (type == Configuration.Collection.Type.CALENDAR) {
|
|
||||||
CalendarDescription calendarDescription = (CalendarDescription)dav.properties.get(CalendarDescription.NAME);
|
|
||||||
if (calendarDescription != null)
|
|
||||||
description = calendarDescription.description;
|
|
||||||
|
|
||||||
CalendarColor calendarColor = (CalendarColor)dav.properties.get(CalendarColor.NAME);
|
|
||||||
if (calendarColor != null)
|
|
||||||
color = calendarColor.color;
|
|
||||||
}
|
|
||||||
|
|
||||||
Configuration.Collection collection = new Configuration.Collection(
|
|
||||||
type,
|
|
||||||
readOnly,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
color
|
|
||||||
);
|
|
||||||
|
|
||||||
return collection;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -432,27 +369,7 @@ public class DavResourceFinder {
|
|||||||
final Set<HttpUrl> homeSets = new HashSet<>();
|
final Set<HttpUrl> homeSets = new HashSet<>();
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
final Map<HttpUrl, Collection> collections = new HashMap<>();
|
final Map<HttpUrl, CollectionInfo> collections = new HashMap<>();
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public static class Collection implements Serializable {
|
|
||||||
public enum Type {
|
|
||||||
ADDRESS_BOOK,
|
|
||||||
CALENDAR
|
|
||||||
}
|
|
||||||
|
|
||||||
final Type type;
|
|
||||||
final boolean readOnly;
|
|
||||||
|
|
||||||
final String displayName, description;
|
|
||||||
final Integer color;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* full VTIMEZONE definition (not the TZ ID)
|
|
||||||
*/
|
|
||||||
boolean supportsEvents, supportsTasks;
|
|
||||||
String timezone;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -26,8 +26,7 @@ import java.io.StringReader;
|
|||||||
|
|
||||||
import at.bitfire.davdroid.Constants;
|
import at.bitfire.davdroid.Constants;
|
||||||
import at.bitfire.davdroid.R;
|
import at.bitfire.davdroid.R;
|
||||||
import at.bitfire.davdroid.resource.DavResourceFinder;
|
import at.bitfire.davdroid.ui.setup.DavResourceFinder.Configuration;
|
||||||
import at.bitfire.davdroid.resource.DavResourceFinder.Configuration;
|
|
||||||
import at.bitfire.davdroid.ui.DebugInfoActivity;
|
import at.bitfire.davdroid.ui.DebugInfoActivity;
|
||||||
import lombok.Cleanup;
|
import lombok.Cleanup;
|
||||||
|
|
||||||
|
@ -46,6 +46,11 @@
|
|||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:indeterminate="true"/>
|
android:indeterminate="true"/>
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/address_books"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</android.support.v7.widget.CardView>
|
</android.support.v7.widget.CardView>
|
||||||
@ -78,6 +83,11 @@
|
|||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:indeterminate="true"/>
|
android:indeterminate="true"/>
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/calendars"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</android.support.v7.widget.CardView>
|
</android.support.v7.widget.CardView>
|
||||||
|
Loading…
Reference in New Issue
Block a user