mirror of
https://github.com/etesync/android
synced 2025-05-24 09:48:49 +00:00
Improved service detection + GUI
* DavService: query group-membership principals for home sets, too * working collection selection * contacts sync according to selected address book
This commit is contained in:
parent
777e124b54
commit
220ba4b151
@ -16,7 +16,6 @@ import android.content.Intent;
|
|||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.DatabaseUtils;
|
import android.database.DatabaseUtils;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
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 android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@ -36,12 +35,9 @@ import at.bitfire.dav4android.UrlUtils;
|
|||||||
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.dav4android.exception.NotFoundException;
|
import at.bitfire.dav4android.exception.NotFoundException;
|
||||||
import at.bitfire.dav4android.property.AddressbookDescription;
|
|
||||||
import at.bitfire.dav4android.property.AddressbookHomeSet;
|
import at.bitfire.dav4android.property.AddressbookHomeSet;
|
||||||
import at.bitfire.dav4android.property.CalendarDescription;
|
|
||||||
import at.bitfire.dav4android.property.CalendarHomeSet;
|
import at.bitfire.dav4android.property.CalendarHomeSet;
|
||||||
import at.bitfire.dav4android.property.DisplayName;
|
import at.bitfire.dav4android.property.GroupMembership;
|
||||||
import at.bitfire.dav4android.property.ResourceType;
|
|
||||||
import at.bitfire.davdroid.model.CollectionInfo;
|
import at.bitfire.davdroid.model.CollectionInfo;
|
||||||
import at.bitfire.davdroid.model.ServiceDB.*;
|
import at.bitfire.davdroid.model.ServiceDB.*;
|
||||||
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
||||||
@ -161,29 +157,32 @@ public class DavService extends Service {
|
|||||||
// create authenticating OkHttpClient (credentials taken from account settings)
|
// create authenticating OkHttpClient (credentials taken from account settings)
|
||||||
OkHttpClient httpClient = httpClient();
|
OkHttpClient httpClient = httpClient();
|
||||||
|
|
||||||
// refresh home sets
|
// refresh home sets: principal
|
||||||
Set<HttpUrl> homeSets = readHomeSets();
|
Set<HttpUrl> homeSets = readHomeSets();
|
||||||
HttpUrl principal = readPrincipal();
|
HttpUrl principal = readPrincipal();
|
||||||
if (principal != null) {
|
if (principal != null) {
|
||||||
Constants.log.debug("[DavService {}] Querying principal for home sets", service);
|
Constants.log.debug("[DavService {}] Querying principal for home sets", service);
|
||||||
DavResource dav = new DavResource(null, httpClient, principal);
|
DavResource dav = new DavResource(null, httpClient, principal);
|
||||||
if (Services.SERVICE_CARDDAV.equals(serviceType)) {
|
queryHomeSets(serviceType, httpClient, principal, homeSets);
|
||||||
dav.propfind(0, AddressbookHomeSet.NAME);
|
|
||||||
AddressbookHomeSet addressbookHomeSet = (AddressbookHomeSet)dav.properties.get(AddressbookHomeSet.NAME);
|
// refresh home sets: direct group memberships
|
||||||
if (addressbookHomeSet != null)
|
GroupMembership groupMembership = (GroupMembership)dav.properties.get(GroupMembership.NAME);
|
||||||
for (String href : addressbookHomeSet.hrefs)
|
if (groupMembership != null)
|
||||||
homeSets.add(UrlUtils.withTrailingSlash(dav.location.resolve(href)));
|
for (String href : groupMembership.hrefs) {
|
||||||
} else if (Services.SERVICE_CALDAV.equals(serviceType)) {
|
Constants.log.debug("[DavService {}] Querying member group {} for home sets", href);
|
||||||
dav.propfind(0, CalendarHomeSet.NAME);
|
queryHomeSets(serviceType, httpClient, dav.location.resolve(href), homeSets);
|
||||||
CalendarHomeSet calendarHomeSet = (CalendarHomeSet)dav.properties.get(CalendarHomeSet.NAME);
|
|
||||||
if (calendarHomeSet != null)
|
|
||||||
for (String href : calendarHomeSet.hrefs)
|
|
||||||
homeSets.add(UrlUtils.withTrailingSlash(dav.location.resolve(href)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// refresh collections in home sets
|
// now refresh collections (taken from home sets)
|
||||||
Map<HttpUrl, CollectionInfo> collections = readCollections();
|
Map<HttpUrl, CollectionInfo> collections = readCollections();
|
||||||
|
|
||||||
|
// (remember selections before)
|
||||||
|
Set<HttpUrl> selectedCollections = new HashSet<>();
|
||||||
|
for (CollectionInfo info : collections.values())
|
||||||
|
if (info.selected)
|
||||||
|
selectedCollections.add(HttpUrl.parse(info.url));
|
||||||
|
|
||||||
for (Iterator<HttpUrl> iterator = homeSets.iterator(); iterator.hasNext();) {
|
for (Iterator<HttpUrl> iterator = homeSets.iterator(); iterator.hasNext();) {
|
||||||
HttpUrl homeSet = iterator.next();
|
HttpUrl homeSet = iterator.next();
|
||||||
Constants.log.debug("[DavService {}] Listing home set {}", service, homeSet);
|
Constants.log.debug("[DavService {}] Listing home set {}", service, homeSet);
|
||||||
@ -229,6 +228,13 @@ public class DavService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restore selections
|
||||||
|
for (HttpUrl url : selectedCollections) {
|
||||||
|
CollectionInfo info = collections.get(url);
|
||||||
|
if (info != null)
|
||||||
|
info.selected = true;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
db.beginTransaction();
|
db.beginTransaction();
|
||||||
saveHomeSets(homeSets);
|
saveHomeSets(homeSets);
|
||||||
@ -249,13 +255,23 @@ public class DavService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String serviceType() {
|
private void queryHomeSets(String serviceType, OkHttpClient client, HttpUrl url, Set<HttpUrl> homeSets) throws IOException, HttpException, DavException {
|
||||||
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[]{Services.SERVICE}, Services.ID + "=?", new String[]{String.valueOf(service)}, null, null, null);
|
DavResource dav = new DavResource(null, client, url);
|
||||||
if (cursor.moveToNext())
|
if (Services.SERVICE_CARDDAV.equals(serviceType)) {
|
||||||
return cursor.getString(0);
|
dav.propfind(0, AddressbookHomeSet.NAME, GroupMembership.NAME);
|
||||||
else
|
AddressbookHomeSet addressbookHomeSet = (AddressbookHomeSet)dav.properties.get(AddressbookHomeSet.NAME);
|
||||||
throw new IllegalArgumentException("Service not found");
|
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, GroupMembership.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)));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private OkHttpClient httpClient() {
|
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);
|
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[]{Services.ACCOUNT_NAME}, Services.ID + "=?", new String[] { String.valueOf(service) }, null, null, null);
|
||||||
@ -270,6 +286,14 @@ public class DavService extends Service {
|
|||||||
throw new IllegalArgumentException("Service not found");
|
throw new IllegalArgumentException("Service not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 HttpUrl readPrincipal() {
|
private HttpUrl readPrincipal() {
|
||||||
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[]{Services.PRINCIPAL}, Services.ID + "=?", new String[]{String.valueOf(service)}, null, null, null);
|
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[]{Services.PRINCIPAL}, Services.ID + "=?", new String[]{String.valueOf(service)}, null, null, null);
|
||||||
if (cursor.moveToNext()) {
|
if (cursor.moveToNext()) {
|
||||||
|
@ -23,7 +23,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
import at.bitfire.dav4android.BasicDigestAuthenticator;
|
import at.bitfire.dav4android.BasicDigestAuthenticator;
|
||||||
import de.duenndns.ssl.MemorizingTrustManager;
|
import de.duenndns.ssl.MemorizingTrustManager;
|
||||||
import lombok.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import okhttp3.Credentials;
|
import okhttp3.Credentials;
|
||||||
import okhttp3.Interceptor;
|
import okhttp3.Interceptor;
|
||||||
|
@ -27,6 +27,7 @@ import at.bitfire.davdroid.model.ServiceDB.*;
|
|||||||
@ToString
|
@ToString
|
||||||
public class CollectionInfo {
|
public class CollectionInfo {
|
||||||
public long id;
|
public long id;
|
||||||
|
public Long serviceID;
|
||||||
|
|
||||||
public enum Type {
|
public enum Type {
|
||||||
ADDRESS_BOOK,
|
ADDRESS_BOOK,
|
||||||
@ -112,6 +113,8 @@ public class CollectionInfo {
|
|||||||
public static CollectionInfo fromDB(ContentValues values) {
|
public static CollectionInfo fromDB(ContentValues values) {
|
||||||
CollectionInfo info = new CollectionInfo();
|
CollectionInfo info = new CollectionInfo();
|
||||||
info.id = values.getAsLong(Collections.ID);
|
info.id = values.getAsLong(Collections.ID);
|
||||||
|
info.serviceID = values.getAsLong(Collections.SERVICE_ID);
|
||||||
|
|
||||||
info.url = values.getAsString(Collections.URL);
|
info.url = values.getAsString(Collections.URL);
|
||||||
info.displayName = values.getAsString(Collections.DISPLAY_NAME);
|
info.displayName = values.getAsString(Collections.DISPLAY_NAME);
|
||||||
info.description = values.getAsString(Collections.DESCRIPTION);
|
info.description = values.getAsString(Collections.DESCRIPTION);
|
||||||
@ -128,6 +131,8 @@ public class CollectionInfo {
|
|||||||
|
|
||||||
public ContentValues toDB() {
|
public ContentValues toDB() {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
|
// Collections.SERVICE_ID is never changed
|
||||||
|
|
||||||
values.put(Collections.URL, url);
|
values.put(Collections.URL, url);
|
||||||
values.put(Collections.DISPLAY_NAME, displayName);
|
values.put(Collections.DISPLAY_NAME, displayName);
|
||||||
values.put(Collections.DESCRIPTION, description);
|
values.put(Collections.DESCRIPTION, description);
|
||||||
|
@ -78,6 +78,14 @@ public class LocalAddressBook extends AndroidAddressBook implements LocalCollect
|
|||||||
return (LocalContact[])queryContacts(AndroidContact.COLUMN_FILENAME + " IS NULL", null);
|
return (LocalContact[])queryContacts(AndroidContact.COLUMN_FILENAME + " IS NULL", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void deleteAll() throws ContactsStorageException {
|
||||||
|
try {
|
||||||
|
provider.delete(syncAdapterURI(RawContacts.CONTENT_URI), null, null);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw new ContactsStorageException("Couldn't delete all local contacts", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// GROUPS
|
// GROUPS
|
||||||
|
|
||||||
|
@ -9,10 +9,8 @@
|
|||||||
package at.bitfire.davdroid.resource;
|
package at.bitfire.davdroid.resource;
|
||||||
|
|
||||||
import android.accounts.Account;
|
import android.accounts.Account;
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.ContentProviderClient;
|
import android.content.ContentProviderClient;
|
||||||
import android.content.ContentProviderOperation;
|
import android.content.ContentProviderOperation;
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.ContentUris;
|
import android.content.ContentUris;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
@ -23,6 +21,7 @@ import android.provider.CalendarContract;
|
|||||||
import android.provider.CalendarContract.Calendars;
|
import android.provider.CalendarContract.Calendars;
|
||||||
import android.provider.CalendarContract.Events;
|
import android.provider.CalendarContract.Events;
|
||||||
import android.provider.CalendarContract.Reminders;
|
import android.provider.CalendarContract.Reminders;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import net.fortuna.ical4j.model.component.VTimeZone;
|
import net.fortuna.ical4j.model.component.VTimeZone;
|
||||||
@ -42,7 +41,6 @@ import at.bitfire.ical4android.CalendarStorageException;
|
|||||||
import at.bitfire.ical4android.DateUtils;
|
import at.bitfire.ical4android.DateUtils;
|
||||||
import at.bitfire.vcard4android.ContactsStorageException;
|
import at.bitfire.vcard4android.ContactsStorageException;
|
||||||
import lombok.Cleanup;
|
import lombok.Cleanup;
|
||||||
import lombok.NonNull;
|
|
||||||
|
|
||||||
public class LocalCalendar extends AndroidCalendar implements LocalCollection {
|
public class LocalCalendar extends AndroidCalendar implements LocalCollection {
|
||||||
|
|
||||||
|
@ -23,5 +23,4 @@ public interface LocalCollection {
|
|||||||
|
|
||||||
String getCTag() throws CalendarStorageException, ContactsStorageException;
|
String getCTag() throws CalendarStorageException, ContactsStorageException;
|
||||||
void setCTag(String cTag) throws CalendarStorageException, ContactsStorageException;
|
void setCTag(String cTag) throws CalendarStorageException, ContactsStorageException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ import at.bitfire.ical4android.AndroidEventFactory;
|
|||||||
import at.bitfire.ical4android.CalendarStorageException;
|
import at.bitfire.ical4android.CalendarStorageException;
|
||||||
import at.bitfire.ical4android.Event;
|
import at.bitfire.ical4android.Event;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
@TargetApi(17)
|
@TargetApi(17)
|
||||||
|
@ -27,7 +27,7 @@ import at.bitfire.ical4android.AndroidTaskList;
|
|||||||
import at.bitfire.ical4android.CalendarStorageException;
|
import at.bitfire.ical4android.CalendarStorageException;
|
||||||
import at.bitfire.ical4android.Task;
|
import at.bitfire.ical4android.Task;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
public class LocalTask extends AndroidTask implements LocalResource {
|
public class LocalTask extends AndroidTask implements LocalResource {
|
||||||
|
@ -26,7 +26,7 @@ import at.bitfire.ical4android.AndroidTaskListFactory;
|
|||||||
import at.bitfire.ical4android.CalendarStorageException;
|
import at.bitfire.ical4android.CalendarStorageException;
|
||||||
import at.bitfire.ical4android.TaskProvider;
|
import at.bitfire.ical4android.TaskProvider;
|
||||||
import lombok.Cleanup;
|
import lombok.Cleanup;
|
||||||
import lombok.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
public class LocalTaskList extends AndroidTaskList implements LocalCollection {
|
public class LocalTaskList extends AndroidTaskList implements LocalCollection {
|
||||||
|
|
||||||
|
@ -35,12 +35,12 @@ import lombok.Cleanup;
|
|||||||
|
|
||||||
public class CalendarsSyncAdapterService extends Service {
|
public class CalendarsSyncAdapterService extends Service {
|
||||||
private static SyncAdapter syncAdapter;
|
private static SyncAdapter syncAdapter;
|
||||||
OpenHelper dbHelper;
|
private OpenHelper dbHelper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
dbHelper = new OpenHelper(this);
|
dbHelper = new OpenHelper(this);
|
||||||
syncAdapter = new SyncAdapter(this, dbHelper);
|
syncAdapter = new SyncAdapter(this, dbHelper.getReadableDatabase());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -55,14 +55,11 @@ public class CalendarsSyncAdapterService extends Service {
|
|||||||
|
|
||||||
|
|
||||||
private static class SyncAdapter extends AbstractThreadedSyncAdapter {
|
private static class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||||
private final OpenHelper dbHelper;
|
|
||||||
private final SQLiteDatabase db;
|
private final SQLiteDatabase db;
|
||||||
|
|
||||||
public SyncAdapter(Context context, OpenHelper dbHelper) {
|
public SyncAdapter(Context context, SQLiteDatabase db) {
|
||||||
super(context, false);
|
super(context, false);
|
||||||
|
this.db = db;
|
||||||
this.dbHelper = dbHelper;
|
|
||||||
db = dbHelper.getReadableDatabase();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -79,8 +76,6 @@ public class CalendarsSyncAdapterService extends Service {
|
|||||||
}
|
}
|
||||||
} catch (CalendarStorageException e) {
|
} catch (CalendarStorageException e) {
|
||||||
Constants.log.error("Couldn't enumerate local calendars", e);
|
Constants.log.error("Couldn't enumerate local calendars", e);
|
||||||
} finally {
|
|
||||||
dbHelper.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Constants.log.info("Calendar sync complete");
|
Constants.log.info("Calendar sync complete");
|
||||||
|
@ -11,26 +11,37 @@ import android.accounts.Account;
|
|||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.AbstractThreadedSyncAdapter;
|
import android.content.AbstractThreadedSyncAdapter;
|
||||||
import android.content.ContentProviderClient;
|
import android.content.ContentProviderClient;
|
||||||
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SyncResult;
|
import android.content.SyncResult;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.DatabaseUtils;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import at.bitfire.davdroid.Constants;
|
import at.bitfire.davdroid.Constants;
|
||||||
|
import at.bitfire.davdroid.model.CollectionInfo;
|
||||||
|
import at.bitfire.davdroid.model.ServiceDB;
|
||||||
|
import at.bitfire.davdroid.model.ServiceDB.Collections;
|
||||||
|
import at.bitfire.davdroid.model.ServiceDB.OpenHelper;
|
||||||
|
import lombok.Cleanup;
|
||||||
|
|
||||||
public class ContactsSyncAdapterService extends Service {
|
public class ContactsSyncAdapterService extends Service {
|
||||||
private static ContactsSyncAdapter syncAdapter;
|
private static ContactsSyncAdapter syncAdapter;
|
||||||
|
private OpenHelper dbHelper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
if (syncAdapter == null)
|
dbHelper = new OpenHelper(this);
|
||||||
syncAdapter = new ContactsSyncAdapter(getApplicationContext());
|
syncAdapter = new ContactsSyncAdapter(this, dbHelper.getReadableDatabase());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
syncAdapter = null;
|
dbHelper.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -40,21 +51,47 @@ public class ContactsSyncAdapterService extends Service {
|
|||||||
|
|
||||||
|
|
||||||
private static class ContactsSyncAdapter extends AbstractThreadedSyncAdapter {
|
private static class ContactsSyncAdapter extends AbstractThreadedSyncAdapter {
|
||||||
public ContactsSyncAdapter(Context context) {
|
private final SQLiteDatabase db;
|
||||||
|
|
||||||
|
public ContactsSyncAdapter(Context context, @NonNull SQLiteDatabase db) {
|
||||||
super(context, false);
|
super(context, false);
|
||||||
|
this.db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
|
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
|
||||||
Constants.log.info("Starting address book sync (" + authority + ")");
|
Constants.log.info("Starting address book sync (" + authority + ")");
|
||||||
|
|
||||||
ContactsSyncManager syncManager = new ContactsSyncManager(getContext(), account, extras, authority, provider, syncResult);
|
long service = getService(account);
|
||||||
|
CollectionInfo remote = remoteAddressBook(service);
|
||||||
|
|
||||||
|
if (remote != null) {
|
||||||
|
ContactsSyncManager syncManager = new ContactsSyncManager(getContext(), account, extras, authority, provider, syncResult, remote);
|
||||||
syncManager.performSync();
|
syncManager.performSync();
|
||||||
|
} else
|
||||||
|
Constants.log.info("No address book collection selected for synchronization");
|
||||||
|
|
||||||
Constants.log.info("Address book sync complete");
|
Constants.log.info("Address book sync complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long getService(@NonNull Account account) {
|
||||||
|
@Cleanup Cursor c = db.query(ServiceDB.Services._TABLE, new String[] { ServiceDB.Services.ID },
|
||||||
|
ServiceDB.Services.ACCOUNT_NAME + "=? AND " + ServiceDB.Services.SERVICE + "=?", new String[] { account.name, ServiceDB.Services.SERVICE_CARDDAV }, null, null, null);
|
||||||
|
c.moveToNext();
|
||||||
|
return c.getLong(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CollectionInfo remoteAddressBook(long service) {
|
||||||
|
@Cleanup Cursor c = db.query(Collections._TABLE, Collections._COLUMNS,
|
||||||
|
Collections.SERVICE_ID + "=? AND selected", new String[] { String.valueOf(service) }, null, null, null);
|
||||||
|
if (c.moveToNext()) {
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
DatabaseUtils.cursorRowToContentValues(c, values);
|
||||||
|
return CollectionInfo.fromDB(values);
|
||||||
|
} else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ import android.content.Context;
|
|||||||
import android.content.SyncResult;
|
import android.content.SyncResult;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import at.bitfire.davdroid.model.CollectionInfo;
|
||||||
|
import at.bitfire.ical4android.CalendarStorageException;
|
||||||
import okhttp3.HttpUrl;
|
import okhttp3.HttpUrl;
|
||||||
import okhttp3.MediaType;
|
import okhttp3.MediaType;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
@ -60,13 +62,15 @@ import lombok.RequiredArgsConstructor;
|
|||||||
public class ContactsSyncManager extends SyncManager {
|
public class ContactsSyncManager extends SyncManager {
|
||||||
protected static final int MAX_MULTIGET = 10;
|
protected static final int MAX_MULTIGET = 10;
|
||||||
|
|
||||||
final protected ContentProviderClient provider;
|
final private ContentProviderClient provider;
|
||||||
protected boolean hasVCard4;
|
final private CollectionInfo remote;
|
||||||
|
private boolean hasVCard4;
|
||||||
|
|
||||||
|
|
||||||
public ContactsSyncManager(Context context, Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult result) {
|
public ContactsSyncManager(Context context, Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult result, CollectionInfo remote) {
|
||||||
super(Constants.NOTIFICATION_CONTACTS_SYNC, context, account, extras, authority, result);
|
super(Constants.NOTIFICATION_CONTACTS_SYNC, context, account, extras, authority, result);
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
|
this.remote = remote;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -80,9 +84,13 @@ public class ContactsSyncManager extends SyncManager {
|
|||||||
// prepare local address book
|
// prepare local address book
|
||||||
localCollection = new LocalAddressBook(account, provider);
|
localCollection = new LocalAddressBook(account, provider);
|
||||||
|
|
||||||
String url = localAddressBook().getURL();
|
String url = remote.url;
|
||||||
if (url == null)
|
String lastUrl = localAddressBook().getURL();
|
||||||
throw new ContactsStorageException("Couldn't get address book URL");
|
if (!url.equals(lastUrl)) {
|
||||||
|
Constants.log.info("Selected address book has changed from {} to {}, deleting all local contacts", lastUrl, url);
|
||||||
|
((LocalAddressBook)localCollection).deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
collectionURL = HttpUrl.parse(url);
|
collectionURL = HttpUrl.parse(url);
|
||||||
davCollection = new DavAddressBook(log, httpClient, collectionURL);
|
davCollection = new DavAddressBook(log, httpClient, collectionURL);
|
||||||
|
|
||||||
@ -204,6 +212,12 @@ public class ContactsSyncManager extends SyncManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void saveSyncState() throws CalendarStorageException, ContactsStorageException {
|
||||||
|
super.saveSyncState();
|
||||||
|
((LocalAddressBook)localCollection).setURL(remote.url);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
|
|
||||||
|
@ -34,12 +34,12 @@ import lombok.Cleanup;
|
|||||||
|
|
||||||
public class TasksSyncAdapterService extends Service {
|
public class TasksSyncAdapterService extends Service {
|
||||||
private static SyncAdapter syncAdapter;
|
private static SyncAdapter syncAdapter;
|
||||||
OpenHelper dbHelper;
|
private OpenHelper dbHelper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
dbHelper = new OpenHelper(this);
|
dbHelper = new OpenHelper(this);
|
||||||
syncAdapter = new SyncAdapter(this, dbHelper);
|
syncAdapter = new SyncAdapter(this, dbHelper.getReadableDatabase());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -54,14 +54,11 @@ public class TasksSyncAdapterService extends Service {
|
|||||||
|
|
||||||
|
|
||||||
private static class SyncAdapter extends AbstractThreadedSyncAdapter {
|
private static class SyncAdapter extends AbstractThreadedSyncAdapter {
|
||||||
private final OpenHelper dbHelper;
|
|
||||||
private final SQLiteDatabase db;
|
private final SQLiteDatabase db;
|
||||||
|
|
||||||
public SyncAdapter(Context context, OpenHelper dbHelper) {
|
public SyncAdapter(Context context, SQLiteDatabase db) {
|
||||||
super(context, false);
|
super(context, false);
|
||||||
|
this.db = db;
|
||||||
this.dbHelper = dbHelper;
|
|
||||||
db = dbHelper.getReadableDatabase();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -31,8 +31,7 @@ import android.os.Build;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.support.v7.view.menu.MenuBuilder;
|
import android.support.v7.widget.AppCompatRadioButton;
|
||||||
import android.support.v7.view.menu.MenuPresenter;
|
|
||||||
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.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@ -41,9 +40,10 @@ import android.view.Menu;
|
|||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.AbsListView;
|
||||||
|
import android.widget.AdapterView;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.CompoundButton;
|
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@ -55,6 +55,7 @@ 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.log.StringLogger;
|
||||||
import at.bitfire.davdroid.model.CollectionInfo;
|
import at.bitfire.davdroid.model.CollectionInfo;
|
||||||
import at.bitfire.davdroid.model.ServiceDB.Collections;
|
import at.bitfire.davdroid.model.ServiceDB.Collections;
|
||||||
import at.bitfire.davdroid.model.ServiceDB.OpenHelper;
|
import at.bitfire.davdroid.model.ServiceDB.OpenHelper;
|
||||||
@ -105,6 +106,9 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
|
case R.id.settings:
|
||||||
|
// TODO
|
||||||
|
break;
|
||||||
case R.id.delete_account:
|
case R.id.delete_account:
|
||||||
new AlertDialog.Builder(AccountActivity.this)
|
new AlertDialog.Builder(AccountActivity.this)
|
||||||
.setIcon(R.drawable.ic_error_dark)
|
.setIcon(R.drawable.ic_error_dark)
|
||||||
@ -161,6 +165,47 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AdapterView.OnItemClickListener onItemClickListener = new AdapterView.OnItemClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
final ListView list = (ListView)parent;
|
||||||
|
final ArrayAdapter<CollectionInfo> adapter = (ArrayAdapter)list.getAdapter();
|
||||||
|
final CollectionInfo info = adapter.getItem(position);
|
||||||
|
|
||||||
|
boolean nowChecked = !info.selected;
|
||||||
|
|
||||||
|
if (list.getChoiceMode() == AbsListView.CHOICE_MODE_SINGLE)
|
||||||
|
// clear all other checked items
|
||||||
|
for (int i = adapter.getCount()-1; i >= 0; i--)
|
||||||
|
adapter.getItem(i).selected = false;
|
||||||
|
|
||||||
|
OpenHelper dbHelper = new OpenHelper(AccountActivity.this);
|
||||||
|
try {
|
||||||
|
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
||||||
|
db.beginTransaction();
|
||||||
|
|
||||||
|
if (list.getChoiceMode() == AbsListView.CHOICE_MODE_SINGLE) {
|
||||||
|
// disable all other collections
|
||||||
|
ContentValues values = new ContentValues(1);
|
||||||
|
values.put(Collections.SELECTED, 0);
|
||||||
|
db.update(Collections._TABLE, values, Collections.SERVICE_ID + "=?", new String[] { String.valueOf(info.serviceID) });
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentValues values = new ContentValues(1);
|
||||||
|
values.put(Collections.SELECTED, nowChecked ? 1 : 0);
|
||||||
|
db.update(Collections._TABLE, values, Collections.ID + "=?", new String[] { String.valueOf(info.id) });
|
||||||
|
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
db.endTransaction();
|
||||||
|
|
||||||
|
info.selected = nowChecked;
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
} finally {
|
||||||
|
dbHelper.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Loader<AccountInfo> onCreateLoader(int id, Bundle args) {
|
public Loader<AccountInfo> onCreateLoader(int id, Bundle args) {
|
||||||
return new AccountLoader(this, args.getString(EXTRA_ACCOUNT_NAME));
|
return new AccountLoader(this, args.getString(EXTRA_ACCOUNT_NAME));
|
||||||
@ -177,9 +222,12 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
|
|
||||||
ListView list = (ListView)findViewById(R.id.address_books);
|
ListView list = (ListView)findViewById(R.id.address_books);
|
||||||
list.setEnabled(!info.carddav.refreshing);
|
list.setEnabled(!info.carddav.refreshing);
|
||||||
|
list.setAlpha(info.carddav.refreshing ? 0.5f : 1);
|
||||||
|
|
||||||
AddressBookAdapter adapter = new AddressBookAdapter(this);
|
AddressBookAdapter adapter = new AddressBookAdapter(this);
|
||||||
adapter.addAll(info.carddav.collections);
|
adapter.addAll(info.carddav.collections);
|
||||||
list.setAdapter(adapter);
|
list.setAdapter(adapter);
|
||||||
|
list.setOnItemClickListener(onItemClickListener);
|
||||||
} else
|
} else
|
||||||
card.setVisibility(View.GONE);
|
card.setVisibility(View.GONE);
|
||||||
|
|
||||||
@ -188,11 +236,14 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
ProgressBar progress = (ProgressBar)findViewById(R.id.caldav_refreshing);
|
ProgressBar progress = (ProgressBar)findViewById(R.id.caldav_refreshing);
|
||||||
progress.setVisibility(info.caldav.refreshing ? View.VISIBLE : View.GONE);
|
progress.setVisibility(info.caldav.refreshing ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
ListView list = (ListView)findViewById(R.id.calendars);
|
final ListView list = (ListView)findViewById(R.id.calendars);
|
||||||
list.setEnabled(!info.caldav.refreshing);
|
list.setEnabled(!info.caldav.refreshing);
|
||||||
CalendarAdapter adapter = new CalendarAdapter(this);
|
list.setAlpha(info.caldav.refreshing ? 0.5f : 1);
|
||||||
|
|
||||||
|
final CalendarAdapter adapter = new CalendarAdapter(this);
|
||||||
adapter.addAll(info.caldav.collections);
|
adapter.addAll(info.caldav.collections);
|
||||||
list.setAdapter(adapter);
|
list.setAdapter(adapter);
|
||||||
|
list.setOnItemClickListener(onItemClickListener);
|
||||||
} else
|
} else
|
||||||
card.setVisibility(View.GONE);
|
card.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
@ -291,15 +342,18 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
|
|
||||||
public static class AddressBookAdapter extends ArrayAdapter<CollectionInfo> {
|
public static class AddressBookAdapter extends ArrayAdapter<CollectionInfo> {
|
||||||
public AddressBookAdapter(Context context) {
|
public AddressBookAdapter(Context context) {
|
||||||
super(context, R.layout.account_address_book_item);
|
super(context, R.layout.account_carddav_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View getView(int position, View v, ViewGroup parent) {
|
public View getView(int position, View v, ViewGroup parent) {
|
||||||
if (v == null)
|
if (v == null)
|
||||||
v = LayoutInflater.from(getContext()).inflate(R.layout.account_address_book_item, parent, false);
|
v = LayoutInflater.from(getContext()).inflate(R.layout.account_carddav_item, parent, false);
|
||||||
|
|
||||||
CollectionInfo info = getItem(position);
|
final CollectionInfo info = getItem(position);
|
||||||
|
|
||||||
|
AppCompatRadioButton checked = (AppCompatRadioButton)v.findViewById(R.id.checked);
|
||||||
|
checked.setChecked(info.selected);
|
||||||
|
|
||||||
TextView tv = (TextView)v.findViewById(R.id.title);
|
TextView tv = (TextView)v.findViewById(R.id.title);
|
||||||
tv.setText(TextUtils.isEmpty(info.displayName) ? info.url : info.displayName);
|
tv.setText(TextUtils.isEmpty(info.displayName) ? info.url : info.displayName);
|
||||||
@ -318,32 +372,18 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
|
|||||||
|
|
||||||
public static class CalendarAdapter extends ArrayAdapter<CollectionInfo> {
|
public static class CalendarAdapter extends ArrayAdapter<CollectionInfo> {
|
||||||
public CalendarAdapter(Context context) {
|
public CalendarAdapter(Context context) {
|
||||||
super(context, R.layout.account_calendar_item);
|
super(context, R.layout.account_caldav_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View getView(int position, View v, ViewGroup parent) {
|
public View getView(final int position, View v, ViewGroup parent) {
|
||||||
if (v == null)
|
if (v == null)
|
||||||
v = LayoutInflater.from(getContext()).inflate(R.layout.account_calendar_item, parent, false);
|
v = LayoutInflater.from(getContext()).inflate(R.layout.account_caldav_item, parent, false);
|
||||||
|
|
||||||
final CollectionInfo info = getItem(position);
|
final CollectionInfo info = getItem(position);
|
||||||
|
|
||||||
CheckBox select = (CheckBox)v.findViewById(R.id.selected);
|
CheckBox checked = (CheckBox)v.findViewById(R.id.checked);
|
||||||
select.setChecked(info.selected);
|
checked.setChecked(info.selected);
|
||||||
select.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
|
||||||
OpenHelper dbHelper = new OpenHelper(getContext());
|
|
||||||
try {
|
|
||||||
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
|
||||||
ContentValues values = new ContentValues(1);
|
|
||||||
values.put(Collections.SELECTED, isChecked ? 1 : 0);
|
|
||||||
db.update(Collections._TABLE, values, Collections.ID + "=?", new String[]{String.valueOf(info.id)});
|
|
||||||
} finally {
|
|
||||||
dbHelper.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (info.color != null) {
|
if (info.color != null) {
|
||||||
View vColor = v.findViewById(R.id.color);
|
View vColor = v.findViewById(R.id.color);
|
||||||
|
@ -48,7 +48,7 @@ import at.bitfire.davdroid.log.StringLogger;
|
|||||||
import at.bitfire.davdroid.model.CollectionInfo;
|
import at.bitfire.davdroid.model.CollectionInfo;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import okhttp3.HttpUrl;
|
import okhttp3.HttpUrl;
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 116 KiB |
@ -16,9 +16,12 @@
|
|||||||
android:gravity="center_vertical">
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@+id/selected"
|
android:id="@+id/checked"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:focusable="false"
|
||||||
|
android:focusableInTouchMode="false"
|
||||||
|
android:clickable="false"
|
||||||
android:layout_marginRight="4dp"/>
|
android:layout_marginRight="4dp"/>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
@ -26,7 +29,7 @@
|
|||||||
android:layout_width="32dp"
|
android:layout_width="32dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginRight="4dp"
|
android:layout_marginRight="4dp"
|
||||||
tools:background="@color/davdroid_green_dark"/>
|
tools:background="@color/green700"/>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
@ -18,7 +18,10 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginRight="4dp"
|
android:layout_marginRight="4dp"
|
||||||
android:id="@+id/checkBox"/>
|
android:focusable="false"
|
||||||
|
android:focusableInTouchMode="false"
|
||||||
|
android:clickable="false"
|
||||||
|
android:id="@+id/checked"/>
|
||||||
|
|
||||||
<LinearLayout android:layout_width="match_parent"
|
<LinearLayout android:layout_width="match_parent"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
@ -7,16 +7,10 @@
|
|||||||
~ http://www.gnu.org/licenses/gpl.html
|
~ http://www.gnu.org/licenses/gpl.html
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:src="@drawable/sky_birds"
|
|
||||||
android:scaleType="centerCrop"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_alignParentTop="true" />
|
android:orientation="vertical">
|
||||||
|
|
||||||
<ListView
|
<ListView
|
||||||
android:id="@id/android:list"
|
android:id="@id/android:list"
|
||||||
@ -36,4 +30,4 @@
|
|||||||
android:textAppearance="@style/TextAppearance.AppCompat.Large"
|
android:textAppearance="@style/TextAppearance.AppCompat.Large"
|
||||||
android:text="@string/account_list_empty" />
|
android:text="@string/account_list_empty" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</LinearLayout>
|
||||||
|
@ -27,15 +27,14 @@
|
|||||||
|
|
||||||
<android.support.design.widget.AppBarLayout
|
<android.support.design.widget.AppBarLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
android:theme="@style/AppTheme.AppBarOverlay">
|
|
||||||
|
|
||||||
<android.support.v7.widget.Toolbar
|
<android.support.v7.widget.Toolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
android:background="?attr/colorPrimary"
|
android:background="?attr/colorPrimary"
|
||||||
app:popupTheme="@style/AppTheme.PopupOverlay"/>
|
/>
|
||||||
</android.support.design.widget.AppBarLayout>
|
</android.support.design.widget.AppBarLayout>
|
||||||
|
|
||||||
<android.support.design.widget.FloatingActionButton
|
<android.support.design.widget.FloatingActionButton
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
@ -41,7 +40,7 @@
|
|||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/carddav_refreshing"
|
android:id="@+id/carddav_refreshing"
|
||||||
style="?android:attr/progressBarStyleHorizontal"
|
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
@ -79,17 +78,18 @@
|
|||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/caldav_refreshing"
|
android:id="@+id/caldav_refreshing"
|
||||||
style="?android:attr/progressBarStyleHorizontal"
|
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:indeterminate="true"/>
|
android:indeterminate="true"/>
|
||||||
|
|
||||||
<ListView
|
<ListView
|
||||||
|
android:id="@+id/calendars"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:choiceMode="multipleChoice"
|
android:choiceMode="multipleChoice"
|
||||||
android:id="@+id/calendars"/>
|
android:descendantFocusability="beforeDescendants"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
@ -7,7 +7,13 @@
|
|||||||
~ http://www.gnu.org/licenses/gpl.html
|
~ http://www.gnu.org/licenses/gpl.html
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item android:id="@+id/settings"
|
||||||
|
android:icon="@drawable/ic_settings_dark"
|
||||||
|
android:title="@string/account_settings"
|
||||||
|
app:showAsAction="always"/>
|
||||||
|
|
||||||
<item android:id="@+id/delete_account"
|
<item android:id="@+id/delete_account"
|
||||||
android:title="@string/account_delete"/>
|
android:title="@string/account_delete"/>
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
<string name="account_list_empty">Welcome to DAVdroid!\n\nYou can add a CalDAV/CardDAV account now.</string>
|
<string name="account_list_empty">Welcome to DAVdroid!\n\nYou can add a CalDAV/CardDAV account now.</string>
|
||||||
|
|
||||||
<!-- AccountActivity -->
|
<!-- AccountActivity -->
|
||||||
|
<string name="account_settings">Account settings</string>
|
||||||
<string name="account_delete">Delete account</string>
|
<string name="account_delete">Delete account</string>
|
||||||
<string name="account_delete_confirmation_title">Really delete account?</string>
|
<string name="account_delete_confirmation_title">Really delete account?</string>
|
||||||
<string name="account_delete_confirmation_text">All local copies of address books, calendars and task lists will be deleted.</string>
|
<string name="account_delete_confirmation_text">All local copies of address books, calendars and task lists will be deleted.</string>
|
||||||
|
@ -10,20 +10,29 @@
|
|||||||
|
|
||||||
<!-- colors -->
|
<!-- colors -->
|
||||||
|
|
||||||
<color name="davdroid_green">#58a434</color>
|
<color name="light_blue_600">#039be5</color>
|
||||||
<color name="davdroid_green_dark">#407826</color>
|
|
||||||
<color name="davdroid_lightblue">#00a8e6</color>
|
<color name="green500">#4caf50</color>
|
||||||
|
<color name="green700">#388e3c</color>
|
||||||
|
|
||||||
|
<color name="light_green300">#aed581</color>
|
||||||
|
<color name="light_green500">#8bc34a</color>
|
||||||
|
<color name="light_green700">#689f38</color>
|
||||||
|
|
||||||
|
<color name="orangeA700">#ff6d00</color>
|
||||||
|
|
||||||
<color name="very_light_grey">#ebebeb</color>
|
<color name="very_light_grey">#ebebeb</color>
|
||||||
|
|
||||||
|
<color name="black">#000000</color>
|
||||||
<color name="white">#ffffff</color>
|
<color name="white">#ffffff</color>
|
||||||
|
|
||||||
|
|
||||||
<!-- app theme -->
|
<!-- app theme -->
|
||||||
|
|
||||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
<style name="AppTheme" parent="Theme.AppCompat.Light">
|
||||||
<item name="colorPrimary">@color/davdroid_green</item>
|
<item name="colorPrimary">@color/light_green500</item>
|
||||||
<item name="colorPrimaryDark">@color/davdroid_green_dark</item>
|
<item name="colorPrimaryDark">@color/light_green700</item>
|
||||||
<item name="colorAccent">@color/davdroid_lightblue</item>
|
<item name="colorAccent">@color/orangeA700</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="AppTheme.NoActionBar">
|
<style name="AppTheme.NoActionBar">
|
||||||
@ -31,8 +40,8 @@
|
|||||||
<item name="windowNoTitle">true</item>
|
<item name="windowNoTitle">true</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
|
<!-- <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
|
||||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
|
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/> -->
|
||||||
|
|
||||||
|
|
||||||
<!-- AddAccountActivity -->
|
<!-- AddAccountActivity -->
|
||||||
@ -76,17 +85,17 @@
|
|||||||
<item name="android:textColorSecondary">@color/white</item>
|
<item name="android:textColorSecondary">@color/white</item>
|
||||||
</style>
|
</style>
|
||||||
<style name="toolbar_style" parent="Widget.AppCompat.Toolbar">
|
<style name="toolbar_style" parent="Widget.AppCompat.Toolbar">
|
||||||
<item name="android:background">@color/davdroid_lightblue</item>
|
<item name="android:background">@color/light_green700</item>
|
||||||
<item name="titleTextColor">@color/white</item>
|
<item name="titleTextColor">@color/white</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<!-- text content -->
|
<!-- text content -->
|
||||||
|
|
||||||
<style name="TextView.Heading" parent="AppTheme">
|
<!-- <style name="TextView.Heading" parent="AppTheme">
|
||||||
<item name="android:padding">5dp</item>
|
<item name="android:padding">5dp</item>
|
||||||
<item name="android:background">#7ca42b</item>
|
<item name="android:background">#7ca42b</item>
|
||||||
<item name="android:textColor">#ffffff</item>
|
<item name="android:textColor">@color/white</item>
|
||||||
</style>
|
</style> -->
|
||||||
|
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in New Issue
Block a user