mirror of
https://github.com/etesync/android
synced 2025-02-18 02:22:08 +00:00
Sync tasks
* remove VJOURNAL/notes sync (will be implemented later) * setup: add "install Tasks app" fragment * version bump to 0.8.0-beta1 * use Tasks instead of Mirakel * handle task list colors * allow independent selection of calendar/task sync for the same CalDAV calendar * minor refactoring (don't use return value of Builder) * handle more task fields and time zones * sync interval setting for tasks
This commit is contained in:
parent
aa7e582bc9
commit
af011a65db
29
app/src/androidTest/res/setup_task_lists_heading.xml
Normal file
29
app/src/androidTest/res/setup_task_lists_heading.xml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (c) 2013 – 2015 Ricki Hirner (bitfire web engineering).
|
||||||
|
~ All rights reserved. This program and the accompanying materials
|
||||||
|
~ are made available under the terms of the GNU Public License v3.0
|
||||||
|
~ which accompanies this distribution, and is available at
|
||||||
|
~ http://www.gnu.org/licenses/gpl.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/TextView.Heading"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:text="@string/setup_task_lists" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="@string/setup_select_task_lists" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="at.bitfire.davdroid"
|
package="at.bitfire.davdroid"
|
||||||
android:versionCode="63" android:versionName="0.7.7"
|
android:versionCode="64" android:versionName="0.8.0-beta1"
|
||||||
android:installLocation="internalOnly">
|
android:installLocation="internalOnly">
|
||||||
|
|
||||||
<uses-sdk
|
<uses-sdk
|
||||||
@ -26,11 +26,8 @@
|
|||||||
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
|
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
|
||||||
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
|
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
|
||||||
|
|
||||||
<uses-permission android:name="at.bitfire.notebooks.provider.READ_WRITE_NOTES" />
|
<uses-permission android:name="org.dmfs.permission.READ_TASKS" />
|
||||||
|
<uses-permission android:name="org.dmfs.permission.WRITE_TASKS" />
|
||||||
<uses-permission android:name="de.azapps.mirakel.provider.READ_WRITE_DATA" />
|
|
||||||
<uses-permission android:name="de.azapps.mirakel.provider.READ_DATA" />
|
|
||||||
<uses-permission android:name="de.azapps.mirakel.provider.WRITE_DATA" />
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@ -73,16 +70,6 @@
|
|||||||
android:name="android.content.SyncAdapter"
|
android:name="android.content.SyncAdapter"
|
||||||
android:resource="@xml/sync_calendars" />
|
android:resource="@xml/sync_calendars" />
|
||||||
</service>
|
</service>
|
||||||
<service
|
|
||||||
android:name=".syncadapter.NotesSyncAdapterService"
|
|
||||||
android:exported="true" >
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.content.SyncAdapter" />
|
|
||||||
</intent-filter>
|
|
||||||
<meta-data
|
|
||||||
android:name="android.content.SyncAdapter"
|
|
||||||
android:resource="@xml/sync_notes" />
|
|
||||||
</service>
|
|
||||||
<service
|
<service
|
||||||
android:name=".syncadapter.TasksSyncAdapterService"
|
android:name=".syncadapter.TasksSyncAdapterService"
|
||||||
android:exported="true" >
|
android:exported="true" >
|
||||||
|
@ -11,7 +11,7 @@ import net.fortuna.ical4j.model.property.ProdId;
|
|||||||
|
|
||||||
public class Constants {
|
public class Constants {
|
||||||
public static final String
|
public static final String
|
||||||
APP_VERSION = "0.7.7",
|
APP_VERSION = "0.8.0-beta1",
|
||||||
ACCOUNT_TYPE = "bitfire.at.davdroid",
|
ACCOUNT_TYPE = "bitfire.at.davdroid",
|
||||||
WEB_URL_HELP = "https://davdroid.bitfire.at/configuration?pk_campaign=davdroid-app",
|
WEB_URL_HELP = "https://davdroid.bitfire.at/configuration?pk_campaign=davdroid-app",
|
||||||
WEB_URL_VIEW_LOGS = "https://github.com/bitfireAT/davdroid/wiki/How-to-view-the-logs";
|
WEB_URL_VIEW_LOGS = "https://github.com/bitfireAT/davdroid/wiki/How-to-view-the-logs";
|
||||||
|
20
app/src/main/java/at/bitfire/davdroid/DAVUtils.java
Normal file
20
app/src/main/java/at/bitfire/davdroid/DAVUtils.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package at.bitfire.davdroid;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class DAVUtils {
|
||||||
|
public static int CalDAVtoARGBColor(String davColor) {
|
||||||
|
int color = 0xFFC3EA6E; // fallback: "DAVdroid green"
|
||||||
|
if (davColor != null) {
|
||||||
|
Pattern p = Pattern.compile("#?(\\p{XDigit}{6})(\\p{XDigit}{2})?");
|
||||||
|
Matcher m = p.matcher(davColor);
|
||||||
|
if (m.find()) {
|
||||||
|
int color_rgb = Integer.parseInt(m.group(1), 16);
|
||||||
|
int color_alpha = m.group(2) != null ? (Integer.parseInt(m.group(2), 16) & 0xFF) : 0xFF;
|
||||||
|
color = (color_alpha << 24) | color_rgb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,10 @@ package at.bitfire.davdroid;
|
|||||||
import android.text.format.Time;
|
import android.text.format.Time;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import net.fortuna.ical4j.model.DefaultTimeZoneRegistryFactory;
|
||||||
|
import net.fortuna.ical4j.model.TimeZone;
|
||||||
|
import net.fortuna.ical4j.model.TimeZoneRegistry;
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
|
||||||
import java.util.SimpleTimeZone;
|
import java.util.SimpleTimeZone;
|
||||||
@ -18,13 +22,16 @@ import java.util.SimpleTimeZone;
|
|||||||
public class DateUtils {
|
public class DateUtils {
|
||||||
private final static String TAG = "davdroid.DateUtils";
|
private final static String TAG = "davdroid.DateUtils";
|
||||||
|
|
||||||
|
private final static TimeZoneRegistry tzRegistry = new DefaultTimeZoneRegistryFactory().createRegistry();
|
||||||
|
|
||||||
|
|
||||||
public static String findAndroidTimezoneID(String tzID) {
|
public static String findAndroidTimezoneID(String tzID) {
|
||||||
String localTZ = null;
|
String localTZ = null;
|
||||||
String availableTZs[] = SimpleTimeZone.getAvailableIDs();
|
String availableTZs[] = SimpleTimeZone.getAvailableIDs();
|
||||||
|
|
||||||
// first, try to find an exact match (case insensitive)
|
// first, try to find an exact match (case insensitive)
|
||||||
for (String availableTZ : availableTZs)
|
for (String availableTZ : availableTZs)
|
||||||
if (tzID.equalsIgnoreCase(availableTZ)) {
|
if (availableTZ.equalsIgnoreCase(tzID)) {
|
||||||
localTZ = availableTZ;
|
localTZ = availableTZ;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -48,4 +55,9 @@ public class DateUtils {
|
|||||||
Log.d(TAG, "Assuming time zone " + localTZ + " for " + tzID);
|
Log.d(TAG, "Assuming time zone " + localTZ + " for " + tzID);
|
||||||
return localTZ;
|
return localTZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TimeZone getTimeZone(String tzID) {
|
||||||
|
return tzRegistry.getTimeZone(tzID);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
package at.bitfire.davdroid.resource;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
|
||||||
import org.simpleframework.xml.Serializer;
|
|
||||||
import org.simpleframework.xml.core.Persister;
|
|
||||||
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
|
|
||||||
import at.bitfire.davdroid.webdav.DavCalendarQuery;
|
|
||||||
import at.bitfire.davdroid.webdav.DavCompFilter;
|
|
||||||
import at.bitfire.davdroid.webdav.DavFilter;
|
|
||||||
import at.bitfire.davdroid.webdav.DavMultiget;
|
|
||||||
import at.bitfire.davdroid.webdav.DavProp;
|
|
||||||
|
|
||||||
public class CalDavNotebook extends RemoteCollection<Note> {
|
|
||||||
private final static String TAG = "davdroid.CalDAVNotebook";
|
|
||||||
|
|
||||||
public CalDavNotebook(CloseableHttpClient httpClient, String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException {
|
|
||||||
super(httpClient, baseURL, user, password, preemptiveAuth);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String memberAcceptedMimeTypes()
|
|
||||||
{
|
|
||||||
return "text/calendar";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected DavMultiget.Type multiGetType() {
|
|
||||||
return DavMultiget.Type.CALENDAR;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Note newResourceSkeleton(String name, String ETag) {
|
|
||||||
return new Note(name, ETag);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMemberETagsQuery() {
|
|
||||||
DavCalendarQuery query = new DavCalendarQuery();
|
|
||||||
|
|
||||||
// prop
|
|
||||||
DavProp prop = new DavProp();
|
|
||||||
prop.setGetetag(new DavProp.GetETag());
|
|
||||||
query.setProp(prop);
|
|
||||||
|
|
||||||
// filter
|
|
||||||
DavFilter filter = new DavFilter();
|
|
||||||
query.setFilter(filter);
|
|
||||||
|
|
||||||
DavCompFilter compFilter = new DavCompFilter("VCALENDAR");
|
|
||||||
filter.setCompFilter(compFilter);
|
|
||||||
|
|
||||||
compFilter.setCompFilter(new DavCompFilter("VJOURNAL"));
|
|
||||||
|
|
||||||
Serializer serializer = new Persister();
|
|
||||||
StringWriter writer = new StringWriter();
|
|
||||||
try {
|
|
||||||
serializer.write(query, writer);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "Couldn't prepare REPORT query", e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return writer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -9,6 +9,7 @@ package at.bitfire.davdroid.resource;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.apache.http.HttpException;
|
import org.apache.http.HttpException;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
@ -127,7 +128,9 @@ public class DavResourceFinder implements Closeable {
|
|||||||
if (homeSetCalendars.getMembers() != null)
|
if (homeSetCalendars.getMembers() != null)
|
||||||
possibleCalendars.addAll(homeSetCalendars.getMembers());
|
possibleCalendars.addAll(homeSetCalendars.getMembers());
|
||||||
|
|
||||||
List<ServerInfo.ResourceInfo> calendars = new LinkedList<>();
|
List<ServerInfo.ResourceInfo>
|
||||||
|
calendars = new LinkedList<>(),
|
||||||
|
todoLists = new LinkedList<>();
|
||||||
for (WebDavResource resource : possibleCalendars)
|
for (WebDavResource resource : possibleCalendars)
|
||||||
if (resource.isCalendar()) {
|
if (resource.isCalendar()) {
|
||||||
Log.i(TAG, "Found calendar: " + resource.getLocation().getPath());
|
Log.i(TAG, "Found calendar: " + resource.getLocation().getPath());
|
||||||
@ -140,36 +143,41 @@ public class DavResourceFinder implements Closeable {
|
|||||||
);
|
);
|
||||||
info.setTimezone(resource.getTimezone());
|
info.setTimezone(resource.getTimezone());
|
||||||
|
|
||||||
|
boolean isCalendar = false,
|
||||||
|
isTodoList = false;
|
||||||
if (resource.getSupportedComponents() == null) {
|
if (resource.getSupportedComponents() == null) {
|
||||||
// no info about supported components, assuming all components are supported
|
// no info about supported components, assuming all components are supported
|
||||||
info.setSupportingEvents(true);
|
isCalendar = true;
|
||||||
info.setSupportingNotes(true);
|
isTodoList = true;
|
||||||
} else {
|
} else {
|
||||||
// CALDAV:supported-calendar-component-set available
|
// CALDAV:supported-calendar-component-set available
|
||||||
for (String supportedComponent : resource.getSupportedComponents())
|
for (String supportedComponent : resource.getSupportedComponents())
|
||||||
if ("VEVENT".equalsIgnoreCase(supportedComponent))
|
if ("VEVENT".equalsIgnoreCase(supportedComponent))
|
||||||
info.setSupportingEvents(true);
|
isCalendar = true;
|
||||||
else if ("VJOURNAL".equalsIgnoreCase(supportedComponent))
|
|
||||||
info.setSupportingNotes(true);
|
|
||||||
else if ("VTODO".equalsIgnoreCase(supportedComponent))
|
else if ("VTODO".equalsIgnoreCase(supportedComponent))
|
||||||
info.setSupportingTasks(true);
|
isTodoList = true;
|
||||||
|
|
||||||
if (!info.isSupportingEvents() && !info.isSupportingNotes() && !info.isSupportingTasks()) {
|
if (!isCalendar && !isTodoList) {
|
||||||
Log.i(TAG, "Ignoring this calendar because it supports neither VEVENT nor VJOURNAL nor VTODO");
|
Log.i(TAG, "Ignoring this calendar because it supports neither VEVENT nor VTODO");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
calendars.add(info);
|
// use a copy constructor to allow different "enabled" status for calendars and todo lists
|
||||||
|
if (isCalendar)
|
||||||
|
calendars.add(new ServerInfo.ResourceInfo(info));
|
||||||
|
if (isTodoList)
|
||||||
|
todoLists.add(new ServerInfo.ResourceInfo(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
serverInfo.setCalendars(calendars);
|
serverInfo.setCalendars(calendars);
|
||||||
|
serverInfo.setTodoLists(todoLists);
|
||||||
} else
|
} else
|
||||||
Log.w(TAG, "Found calendar home set, but it doesn't advertise CalDAV support");
|
Log.w(TAG, "Found calendar home set, but it doesn't advertise CalDAV support");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!serverInfo.isCalDAV() && !serverInfo.isCardDAV())
|
if (!serverInfo.isCalDAV() && !serverInfo.isCardDAV())
|
||||||
throw new DavIncapableException(context.getString(R.string.setup_neither_caldav_nor_carddav));
|
throw new DavIncapableException(context.getString(R.string.setup_neither_caldav_nor_carddav));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -658,8 +658,7 @@ public class LocalAddressBook extends LocalCollection<Contact> {
|
|||||||
Contact contact = (Contact)resource;
|
Contact contact = (Contact)resource;
|
||||||
|
|
||||||
if (!update)
|
if (!update)
|
||||||
builder = builder
|
builder .withValue(RawContacts.ACCOUNT_NAME, account.name)
|
||||||
.withValue(RawContacts.ACCOUNT_NAME, account.name)
|
|
||||||
.withValue(RawContacts.ACCOUNT_TYPE, account.type);
|
.withValue(RawContacts.ACCOUNT_TYPE, account.type);
|
||||||
|
|
||||||
return builder
|
return builder
|
||||||
@ -800,14 +799,13 @@ public class LocalAddressBook extends LocalCollection<Contact> {
|
|||||||
typeLabel = xNameToLabel(type.getValue());
|
typeLabel = xNameToLabel(type.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
builder = builder
|
builder .withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
|
||||||
.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
|
.withValue(Phone.NUMBER, number.getText())
|
||||||
.withValue(Phone.NUMBER, number.getText())
|
.withValue(Phone.TYPE, typeCode)
|
||||||
.withValue(Phone.TYPE, typeCode)
|
.withValue(Phone.IS_PRIMARY, is_primary ? 1 : 0)
|
||||||
.withValue(Phone.IS_PRIMARY, is_primary ? 1 : 0)
|
.withValue(Phone.IS_SUPER_PRIMARY, is_primary ? 1 : 0);
|
||||||
.withValue(Phone.IS_SUPER_PRIMARY, is_primary ? 1 : 0);
|
|
||||||
if (typeLabel != null)
|
if (typeLabel != null)
|
||||||
builder = builder.withValue(Phone.LABEL, typeLabel);
|
builder.withValue(Phone.LABEL, typeLabel);
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -834,14 +832,13 @@ public class LocalAddressBook extends LocalCollection<Contact> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
builder = builder
|
builder .withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE)
|
||||||
.withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE)
|
|
||||||
.withValue(Email.ADDRESS, email.getValue())
|
.withValue(Email.ADDRESS, email.getValue())
|
||||||
.withValue(Email.TYPE, typeCode)
|
.withValue(Email.TYPE, typeCode)
|
||||||
.withValue(Email.IS_PRIMARY, is_primary ? 1 : 0)
|
.withValue(Email.IS_PRIMARY, is_primary ? 1 : 0)
|
||||||
.withValue(Phone.IS_SUPER_PRIMARY, is_primary ? 1 : 0);
|
.withValue(Phone.IS_SUPER_PRIMARY, is_primary ? 1 : 0);
|
||||||
if (typeLabel != null)
|
if (typeLabel != null)
|
||||||
builder = builder.withValue(Email.LABEL, typeLabel);
|
builder.withValue(Email.LABEL, typeLabel);
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -928,22 +925,20 @@ public class LocalAddressBook extends LocalCollection<Contact> {
|
|||||||
|
|
||||||
if (sipAddress)
|
if (sipAddress)
|
||||||
// save as SIP address
|
// save as SIP address
|
||||||
builder = builder
|
builder .withValue(Data.MIMETYPE, SipAddress.CONTENT_ITEM_TYPE)
|
||||||
.withValue(Data.MIMETYPE, SipAddress.CONTENT_ITEM_TYPE)
|
.withValue(Im.DATA, impp.getHandle())
|
||||||
.withValue(Im.DATA, impp.getHandle())
|
.withValue(Im.TYPE, typeCode);
|
||||||
.withValue(Im.TYPE, typeCode);
|
|
||||||
else {
|
else {
|
||||||
// save as IM address
|
// save as IM address
|
||||||
builder = builder
|
builder .withValue(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE)
|
||||||
.withValue(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE)
|
.withValue(Im.DATA, impp.getHandle())
|
||||||
.withValue(Im.DATA, impp.getHandle())
|
.withValue(Im.TYPE, typeCode)
|
||||||
.withValue(Im.TYPE, typeCode)
|
.withValue(Im.PROTOCOL, protocolCode);
|
||||||
.withValue(Im.PROTOCOL, protocolCode);
|
|
||||||
if (protocolLabel != null)
|
if (protocolLabel != null)
|
||||||
builder = builder.withValue(Im.CUSTOM_PROTOCOL, protocolLabel);
|
builder.withValue(Im.CUSTOM_PROTOCOL, protocolLabel);
|
||||||
}
|
}
|
||||||
if (typeLabel != null)
|
if (typeLabel != null)
|
||||||
builder = builder.withValue(Im.LABEL, typeLabel);
|
builder.withValue(Im.LABEL, typeLabel);
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -996,19 +991,18 @@ public class LocalAddressBook extends LocalCollection<Contact> {
|
|||||||
typeLabel = xNameToLabel(address.getTypes().iterator().next().getValue());
|
typeLabel = xNameToLabel(address.getTypes().iterator().next().getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
builder = builder
|
builder .withValue(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE)
|
||||||
.withValue(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE)
|
.withValue(StructuredPostal.FORMATTED_ADDRESS, formattedAddress)
|
||||||
.withValue(StructuredPostal.FORMATTED_ADDRESS, formattedAddress)
|
.withValue(StructuredPostal.TYPE, typeCode)
|
||||||
.withValue(StructuredPostal.TYPE, typeCode)
|
.withValue(StructuredPostal.STREET, address.getStreetAddress())
|
||||||
.withValue(StructuredPostal.STREET, address.getStreetAddress())
|
.withValue(StructuredPostal.POBOX, address.getPoBox())
|
||||||
.withValue(StructuredPostal.POBOX, address.getPoBox())
|
.withValue(StructuredPostal.NEIGHBORHOOD, address.getExtendedAddress())
|
||||||
.withValue(StructuredPostal.NEIGHBORHOOD, address.getExtendedAddress())
|
.withValue(StructuredPostal.CITY, address.getLocality())
|
||||||
.withValue(StructuredPostal.CITY, address.getLocality())
|
.withValue(StructuredPostal.REGION, address.getRegion())
|
||||||
.withValue(StructuredPostal.REGION, address.getRegion())
|
.withValue(StructuredPostal.POSTCODE, address.getPostalCode())
|
||||||
.withValue(StructuredPostal.POSTCODE, address.getPostalCode())
|
.withValue(StructuredPostal.COUNTRY, address.getCountry());
|
||||||
.withValue(StructuredPostal.COUNTRY, address.getCountry());
|
|
||||||
if (typeLabel != null)
|
if (typeLabel != null)
|
||||||
builder = builder.withValue(StructuredPostal.LABEL, typeLabel);
|
builder.withValue(StructuredPostal.LABEL, typeLabel);
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@ import java.util.List;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import at.bitfire.davdroid.DAVUtils;
|
||||||
import at.bitfire.davdroid.DateUtils;
|
import at.bitfire.davdroid.DateUtils;
|
||||||
import lombok.Cleanup;
|
import lombok.Cleanup;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@ -120,24 +121,13 @@ public class LocalCalendar extends LocalCollection<Event> {
|
|||||||
final ContentProviderClient client = resolver.acquireContentProviderClient(CalendarContract.AUTHORITY);
|
final ContentProviderClient client = resolver.acquireContentProviderClient(CalendarContract.AUTHORITY);
|
||||||
if (client == null)
|
if (client == null)
|
||||||
throw new LocalStorageException("No Calendar Provider found (Calendar app disabled?)");
|
throw new LocalStorageException("No Calendar Provider found (Calendar app disabled?)");
|
||||||
|
|
||||||
int color = 0xFFC3EA6E; // fallback: "DAVdroid green"
|
|
||||||
if (info.getColor() != null) {
|
|
||||||
Pattern p = Pattern.compile("#?(\\p{XDigit}{6})(\\p{XDigit}{2})?");
|
|
||||||
Matcher m = p.matcher(info.getColor());
|
|
||||||
if (m.find()) {
|
|
||||||
int color_rgb = Integer.parseInt(m.group(1), 16);
|
|
||||||
int color_alpha = m.group(2) != null ? (Integer.parseInt(m.group(2), 16) & 0xFF) : 0xFF;
|
|
||||||
color = (color_alpha << 24) | color_rgb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(Calendars.ACCOUNT_NAME, account.name);
|
values.put(Calendars.ACCOUNT_NAME, account.name);
|
||||||
values.put(Calendars.ACCOUNT_TYPE, account.type);
|
values.put(Calendars.ACCOUNT_TYPE, account.type);
|
||||||
values.put(Calendars.NAME, info.getURL());
|
values.put(Calendars.NAME, info.getURL());
|
||||||
values.put(Calendars.CALENDAR_DISPLAY_NAME, info.getTitle());
|
values.put(Calendars.CALENDAR_DISPLAY_NAME, info.getTitle());
|
||||||
values.put(Calendars.CALENDAR_COLOR, color);
|
values.put(Calendars.CALENDAR_COLOR, DAVUtils.CalDAVtoARGBColor(info.getColor()));
|
||||||
values.put(Calendars.OWNER_ACCOUNT, account.name);
|
values.put(Calendars.OWNER_ACCOUNT, account.name);
|
||||||
values.put(Calendars.SYNC_EVENTS, 1);
|
values.put(Calendars.SYNC_EVENTS, 1);
|
||||||
values.put(Calendars.VISIBLE, 1);
|
values.put(Calendars.VISIBLE, 1);
|
||||||
@ -527,12 +517,10 @@ public class LocalCalendar extends LocalCollection<Event> {
|
|||||||
final Event event = (Event)resource;
|
final Event event = (Event)resource;
|
||||||
|
|
||||||
if (!update)
|
if (!update)
|
||||||
builder = builder
|
builder .withValue(Events.ACCOUNT_TYPE, account.type)
|
||||||
.withValue(Events.ACCOUNT_TYPE, account.type)
|
|
||||||
.withValue(Events.ACCOUNT_NAME, account.name);
|
.withValue(Events.ACCOUNT_NAME, account.name);
|
||||||
|
|
||||||
builder = builder
|
builder .withValue(Events.CALENDAR_ID, id)
|
||||||
.withValue(Events.CALENDAR_ID, id)
|
|
||||||
.withValue(Events.ALL_DAY, event.isAllDay() ? 1 : 0)
|
.withValue(Events.ALL_DAY, event.isAllDay() ? 1 : 0)
|
||||||
.withValue(Events.DTSTART, event.getDtStartInMillis())
|
.withValue(Events.DTSTART, event.getDtStartInMillis())
|
||||||
.withValue(Events.EVENT_TIMEZONE, event.getDtStartTzID())
|
.withValue(Events.EVENT_TIMEZONE, event.getDtStartTzID())
|
||||||
@ -545,12 +533,11 @@ public class LocalCalendar extends LocalCollection<Event> {
|
|||||||
final RecurrenceId recurrenceId = event.getRecurrenceId();
|
final RecurrenceId recurrenceId = event.getRecurrenceId();
|
||||||
if (recurrenceId == null) {
|
if (recurrenceId == null) {
|
||||||
// this event is a "master event" (not an exception)
|
// this event is a "master event" (not an exception)
|
||||||
builder = builder
|
builder .withValue(entryColumnRemoteName(), event.getName())
|
||||||
.withValue(entryColumnRemoteName(), event.getName())
|
|
||||||
.withValue(entryColumnETag(), event.getETag())
|
.withValue(entryColumnETag(), event.getETag())
|
||||||
.withValue(entryColumnUID(), event.getUid());
|
.withValue(entryColumnUID(), event.getUid());
|
||||||
} else {
|
} else {
|
||||||
builder = builder.withValue(Events.ORIGINAL_SYNC_ID, event.getName());
|
builder.withValue(Events.ORIGINAL_SYNC_ID, event.getName());
|
||||||
|
|
||||||
// ORIGINAL_INSTANCE_TIME and ORIGINAL_ALL_DAY is set in buildExceptions.
|
// ORIGINAL_INSTANCE_TIME and ORIGINAL_ALL_DAY is set in buildExceptions.
|
||||||
// It's not possible to use only the RECURRENCE-ID to calculate
|
// It's not possible to use only the RECURRENCE-ID to calculate
|
||||||
@ -561,40 +548,38 @@ public class LocalCalendar extends LocalCollection<Event> {
|
|||||||
boolean recurring = false;
|
boolean recurring = false;
|
||||||
if (event.getRrule() != null) {
|
if (event.getRrule() != null) {
|
||||||
recurring = true;
|
recurring = true;
|
||||||
builder = builder.withValue(Events.RRULE, event.getRrule().getValue());
|
builder.withValue(Events.RRULE, event.getRrule().getValue());
|
||||||
}
|
}
|
||||||
if (!event.getRdates().isEmpty()) {
|
if (!event.getRdates().isEmpty()) {
|
||||||
recurring = true;
|
recurring = true;
|
||||||
builder = builder.withValue(Events.RDATE, recurrenceSetsToAndroidString(event.getRdates()));
|
builder.withValue(Events.RDATE, recurrenceSetsToAndroidString(event.getRdates()));
|
||||||
}
|
}
|
||||||
if (event.getExrule() != null)
|
if (event.getExrule() != null)
|
||||||
builder = builder.withValue(Events.EXRULE, event.getExrule().getValue());
|
builder.withValue(Events.EXRULE, event.getExrule().getValue());
|
||||||
if (!event.getExdates().isEmpty())
|
if (!event.getExdates().isEmpty())
|
||||||
builder = builder.withValue(Events.EXDATE, recurrenceSetsToAndroidString(event.getExdates()));
|
builder.withValue(Events.EXDATE, recurrenceSetsToAndroidString(event.getExdates()));
|
||||||
|
|
||||||
// set either DTEND for single-time events or DURATION for recurring events
|
// set either DTEND for single-time events or DURATION for recurring events
|
||||||
// because that's the way Android likes it (see docs)
|
// because that's the way Android likes it (see docs)
|
||||||
if (recurring) {
|
if (recurring) {
|
||||||
// calculate DURATION from start and end date
|
// calculate DURATION from start and end date
|
||||||
Duration duration = new Duration(event.getDtStart().getDate(), event.getDtEnd().getDate());
|
Duration duration = new Duration(event.getDtStart().getDate(), event.getDtEnd().getDate());
|
||||||
builder = builder.withValue(Events.DURATION, duration.getValue());
|
builder.withValue(Events.DURATION, duration.getValue());
|
||||||
} else {
|
} else
|
||||||
builder = builder
|
builder .withValue(Events.DTEND, event.getDtEndInMillis())
|
||||||
.withValue(Events.DTEND, event.getDtEndInMillis())
|
|
||||||
.withValue(Events.EVENT_END_TIMEZONE, event.getDtEndTzID());
|
.withValue(Events.EVENT_END_TIMEZONE, event.getDtEndTzID());
|
||||||
}
|
|
||||||
|
|
||||||
if (event.getSummary() != null)
|
if (event.getSummary() != null)
|
||||||
builder = builder.withValue(Events.TITLE, event.getSummary());
|
builder.withValue(Events.TITLE, event.getSummary());
|
||||||
if (event.getLocation() != null)
|
if (event.getLocation() != null)
|
||||||
builder = builder.withValue(Events.EVENT_LOCATION, event.getLocation());
|
builder.withValue(Events.EVENT_LOCATION, event.getLocation());
|
||||||
if (event.getDescription() != null)
|
if (event.getDescription() != null)
|
||||||
builder = builder.withValue(Events.DESCRIPTION, event.getDescription());
|
builder.withValue(Events.DESCRIPTION, event.getDescription());
|
||||||
|
|
||||||
if (event.getOrganizer() != null && event.getOrganizer().getCalAddress() != null) {
|
if (event.getOrganizer() != null && event.getOrganizer().getCalAddress() != null) {
|
||||||
URI organizer = event.getOrganizer().getCalAddress();
|
URI organizer = event.getOrganizer().getCalAddress();
|
||||||
if (organizer.getScheme() != null && organizer.getScheme().equalsIgnoreCase("mailto"))
|
if (organizer.getScheme() != null && organizer.getScheme().equalsIgnoreCase("mailto"))
|
||||||
builder = builder.withValue(Events.ORGANIZER, organizer.getSchemeSpecificPart());
|
builder.withValue(Events.ORGANIZER, organizer.getSchemeSpecificPart());
|
||||||
}
|
}
|
||||||
|
|
||||||
Status status = event.getStatus();
|
Status status = event.getStatus();
|
||||||
@ -604,13 +589,13 @@ public class LocalCalendar extends LocalCollection<Event> {
|
|||||||
statusCode = Events.STATUS_CONFIRMED;
|
statusCode = Events.STATUS_CONFIRMED;
|
||||||
else if (status == Status.VEVENT_CANCELLED)
|
else if (status == Status.VEVENT_CANCELLED)
|
||||||
statusCode = Events.STATUS_CANCELED;
|
statusCode = Events.STATUS_CANCELED;
|
||||||
builder = builder.withValue(Events.STATUS, statusCode);
|
builder.withValue(Events.STATUS, statusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
builder = builder.withValue(Events.AVAILABILITY, event.isOpaque() ? Events.AVAILABILITY_BUSY : Events.AVAILABILITY_FREE);
|
builder.withValue(Events.AVAILABILITY, event.isOpaque() ? Events.AVAILABILITY_BUSY : Events.AVAILABILITY_FREE);
|
||||||
|
|
||||||
if (event.getForPublic() != null)
|
if (event.getForPublic() != null)
|
||||||
builder = builder.withValue(Events.ACCESS_LEVEL, event.getForPublic() ? Events.ACCESS_PUBLIC : Events.ACCESS_PRIVATE);
|
builder.withValue(Events.ACCESS_LEVEL, event.getForPublic() ? Events.ACCESS_PUBLIC : Events.ACCESS_PRIVATE);
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
@ -683,7 +668,7 @@ public class LocalCalendar extends LocalCollection<Event> {
|
|||||||
|
|
||||||
final Cn cn = (Cn)attendee.getParameter(Parameter.CN);
|
final Cn cn = (Cn)attendee.getParameter(Parameter.CN);
|
||||||
if (cn != null)
|
if (cn != null)
|
||||||
builder = builder.withValue(Attendees.ATTENDEE_NAME, cn.getValue());
|
builder.withValue(Attendees.ATTENDEE_NAME, cn.getValue());
|
||||||
|
|
||||||
int type = Attendees.TYPE_NONE;
|
int type = Attendees.TYPE_NONE;
|
||||||
|
|
||||||
@ -702,7 +687,7 @@ public class LocalCalendar extends LocalCollection<Event> {
|
|||||||
else if (role == Role.REQ_PARTICIPANT)
|
else if (role == Role.REQ_PARTICIPANT)
|
||||||
type = Attendees.TYPE_REQUIRED;
|
type = Attendees.TYPE_REQUIRED;
|
||||||
}
|
}
|
||||||
builder = builder.withValue(Attendees.ATTENDEE_RELATIONSHIP, relationship);
|
builder.withValue(Attendees.ATTENDEE_RELATIONSHIP, relationship);
|
||||||
}
|
}
|
||||||
|
|
||||||
int status = Attendees.ATTENDEE_STATUS_NONE;
|
int status = Attendees.ATTENDEE_STATUS_NONE;
|
||||||
|
@ -1,179 +0,0 @@
|
|||||||
package at.bitfire.davdroid.resource;
|
|
||||||
|
|
||||||
import android.accounts.Account;
|
|
||||||
import android.content.ContentProviderClient;
|
|
||||||
import android.content.ContentProviderOperation;
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.ContentUris;
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.DatabaseUtils;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.provider.CalendarContract;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import net.fortuna.ical4j.model.DateTime;
|
|
||||||
import net.fortuna.ical4j.model.property.Created;
|
|
||||||
import net.fortuna.ical4j.model.property.DtStamp;
|
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import at.bitfire.davdroid.Constants;
|
|
||||||
import at.bitfire.notebooks.provider.NoteContract;
|
|
||||||
import lombok.Cleanup;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
public class LocalNotebook extends LocalCollection<Note> {
|
|
||||||
private final static String TAG = "davdroid.LocalNotebook";
|
|
||||||
|
|
||||||
@Getter protected final String url;
|
|
||||||
@Getter protected final long id;
|
|
||||||
|
|
||||||
protected static String COLLECTION_COLUMN_CTAG = NoteContract.Notebooks.SYNC1;
|
|
||||||
|
|
||||||
@Override protected Uri entriesURI() { return syncAdapterURI(NoteContract.Notes.CONTENT_URI); }
|
|
||||||
@Override protected String entryColumnAccountType() { return NoteContract.Notes.ACCOUNT_TYPE; }
|
|
||||||
@Override protected String entryColumnAccountName() { return NoteContract.Notes.ACCOUNT_NAME; }
|
|
||||||
@Override protected String entryColumnParentID() { return NoteContract.Notes.NOTEBOOK_ID; }
|
|
||||||
@Override protected String entryColumnID() { return NoteContract.Notes._ID; }
|
|
||||||
@Override protected String entryColumnRemoteName() { return NoteContract.Notes._SYNC_ID; }
|
|
||||||
@Override protected String entryColumnETag() { return NoteContract.Notes.SYNC1; }
|
|
||||||
@Override protected String entryColumnDirty() { return NoteContract.Notes.DIRTY; }
|
|
||||||
@Override protected String entryColumnDeleted() { return NoteContract.Notes.DELETED; }
|
|
||||||
@Override protected String entryColumnUID() { return NoteContract.Notes.UID; }
|
|
||||||
|
|
||||||
|
|
||||||
public static Uri create(Account account, ContentResolver resolver, ServerInfo.ResourceInfo info) throws LocalStorageException {
|
|
||||||
final ContentProviderClient client = resolver.acquireContentProviderClient(NoteContract.AUTHORITY);
|
|
||||||
if (client == null)
|
|
||||||
throw new LocalStorageException("No notes provider found");
|
|
||||||
|
|
||||||
ContentValues values = new ContentValues();
|
|
||||||
values.put(NoteContract.Notebooks._SYNC_ID, info.getURL());
|
|
||||||
values.put(NoteContract.Notebooks.NAME, info.getTitle());
|
|
||||||
|
|
||||||
Log.i(TAG, "Inserting notebook: " + values.toString());
|
|
||||||
try {
|
|
||||||
return client.insert(notebooksURI(account), values);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
throw new LocalStorageException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LocalNotebook[] findAll(Account account, ContentProviderClient providerClient) throws RemoteException {
|
|
||||||
@Cleanup Cursor cursor = providerClient.query(notebooksURI(account),
|
|
||||||
new String[] { NoteContract.Notebooks._ID, NoteContract.Notebooks._SYNC_ID },
|
|
||||||
NoteContract.Notebooks.DELETED + "=0", null, null);
|
|
||||||
|
|
||||||
LinkedList<LocalNotebook> notebooks = new LinkedList<>();
|
|
||||||
while (cursor != null && cursor.moveToNext())
|
|
||||||
notebooks.add(new LocalNotebook(account, providerClient, cursor.getInt(0), cursor.getString(1)));
|
|
||||||
return notebooks.toArray(new LocalNotebook[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocalNotebook(Account account, ContentProviderClient providerClient, long id, String url) throws RemoteException {
|
|
||||||
super(account, providerClient);
|
|
||||||
this.id = id;
|
|
||||||
this.url = url;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCTag() throws LocalStorageException {
|
|
||||||
try {
|
|
||||||
@Cleanup Cursor c = providerClient.query(ContentUris.withAppendedId(notebooksURI(account), id),
|
|
||||||
new String[] { COLLECTION_COLUMN_CTAG }, null, null, null);
|
|
||||||
if (c != null && c.moveToFirst())
|
|
||||||
return c.getString(0);
|
|
||||||
else
|
|
||||||
throw new LocalStorageException("Couldn't query notebook CTag");
|
|
||||||
} catch(RemoteException e) {
|
|
||||||
throw new LocalStorageException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCTag(String cTag) throws LocalStorageException {
|
|
||||||
ContentValues values = new ContentValues(1);
|
|
||||||
values.put(COLLECTION_COLUMN_CTAG, cTag);
|
|
||||||
try {
|
|
||||||
providerClient.update(ContentUris.withAppendedId(notebooksURI(account), id), values, null, null);
|
|
||||||
} catch(RemoteException e) {
|
|
||||||
throw new LocalStorageException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Note newResource(long localID, String resourceName, String eTag) {
|
|
||||||
return new Note(localID, resourceName, eTag);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void populate(Resource record) throws LocalStorageException {
|
|
||||||
try {
|
|
||||||
@Cleanup final Cursor cursor = providerClient.query(entriesURI(),
|
|
||||||
new String[] {
|
|
||||||
/* 0 */ entryColumnUID(), NoteContract.Notes.CREATED_AT, NoteContract.Notes.UPDATED_AT, NoteContract.Notes.DTSTART,
|
|
||||||
/* 4 */ NoteContract.Notes.SUMMARY, NoteContract.Notes.DESCRIPTION, NoteContract.Notes.COMMENT,
|
|
||||||
/* 7 */ NoteContract.Notes.ORGANIZER, NoteContract.Notes.STATUS, NoteContract.Notes.CLASSIFICATION,
|
|
||||||
/* 10 */ NoteContract.Notes.CONTACT, NoteContract.Notes.URL
|
|
||||||
}, entryColumnID() + "=?", new String[]{ String.valueOf(record.getLocalID()) }, null);
|
|
||||||
|
|
||||||
Note note = (Note)record;
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
|
||||||
note.setUid(cursor.getString(0));
|
|
||||||
|
|
||||||
if (!cursor.isNull(1))
|
|
||||||
note.setCreated(new Created(new DateTime(cursor.getLong(1))));
|
|
||||||
|
|
||||||
note.setSummary(cursor.getString(4));
|
|
||||||
note.setDescription(cursor.getString(5));
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
throw new LocalStorageException("Couldn't process locally stored note", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ContentProviderOperation.Builder buildEntry(ContentProviderOperation.Builder builder, Resource resource, boolean update) {
|
|
||||||
final Note note = (Note)resource;
|
|
||||||
builder = builder
|
|
||||||
.withValue(entryColumnParentID(), id)
|
|
||||||
.withValue(entryColumnRemoteName(), note.getName())
|
|
||||||
.withValue(entryColumnUID(), note.getUid())
|
|
||||||
.withValue(entryColumnETag(), note.getETag())
|
|
||||||
.withValue(NoteContract.Notes.SUMMARY, note.getSummary())
|
|
||||||
.withValue(NoteContract.Notes.DESCRIPTION, note.getDescription());
|
|
||||||
|
|
||||||
if (note.getCreated() != null)
|
|
||||||
builder = builder.withValue(NoteContract.Notes.CREATED_AT, note.getCreated().getDateTime().getTime());
|
|
||||||
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void addDataRows(Resource resource, long localID, int backrefIdx) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void removeDataRows(Resource resource) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// helpers
|
|
||||||
|
|
||||||
protected static Uri notebooksURI(Account account) {
|
|
||||||
return NoteContract.Notebooks.CONTENT_URI.buildUpon()
|
|
||||||
.appendQueryParameter(NoteContract.Notebooks.ACCOUNT_TYPE, account.type)
|
|
||||||
.appendQueryParameter(NoteContract.Notebooks.ACCOUNT_NAME, account.name)
|
|
||||||
.appendQueryParameter(NoteContract.CALLER_IS_SYNCADAPTER, "true")
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,6 +6,7 @@ import android.content.ContentProviderOperation;
|
|||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.ContentUris;
|
import android.content.ContentUris;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@ -13,15 +14,25 @@ import android.util.Log;
|
|||||||
|
|
||||||
import net.fortuna.ical4j.model.Date;
|
import net.fortuna.ical4j.model.Date;
|
||||||
import net.fortuna.ical4j.model.DateTime;
|
import net.fortuna.ical4j.model.DateTime;
|
||||||
|
import net.fortuna.ical4j.model.Dur;
|
||||||
|
import net.fortuna.ical4j.model.TimeZone;
|
||||||
|
import net.fortuna.ical4j.model.TimeZoneRegistry;
|
||||||
import net.fortuna.ical4j.model.property.Clazz;
|
import net.fortuna.ical4j.model.property.Clazz;
|
||||||
import net.fortuna.ical4j.model.property.Completed;
|
import net.fortuna.ical4j.model.property.Completed;
|
||||||
|
import net.fortuna.ical4j.model.property.Created;
|
||||||
import net.fortuna.ical4j.model.property.DtStart;
|
import net.fortuna.ical4j.model.property.DtStart;
|
||||||
|
import net.fortuna.ical4j.model.property.Due;
|
||||||
|
import net.fortuna.ical4j.model.property.Duration;
|
||||||
import net.fortuna.ical4j.model.property.Status;
|
import net.fortuna.ical4j.model.property.Status;
|
||||||
|
import net.fortuna.ical4j.util.TimeZones;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.dmfs.provider.tasks.TaskContract;
|
import org.dmfs.provider.tasks.TaskContract;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
import at.bitfire.davdroid.DAVUtils;
|
||||||
|
import at.bitfire.davdroid.DateUtils;
|
||||||
import lombok.Cleanup;
|
import lombok.Cleanup;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@ -31,9 +42,11 @@ public class LocalTaskList extends LocalCollection<Task> {
|
|||||||
@Getter protected String url;
|
@Getter protected String url;
|
||||||
@Getter protected long id;
|
@Getter protected long id;
|
||||||
|
|
||||||
|
public static final String TASKS_AUTHORITY = "org.dmfs.tasks";
|
||||||
|
|
||||||
protected static String COLLECTION_COLUMN_CTAG = TaskContract.TaskLists.SYNC1;
|
protected static String COLLECTION_COLUMN_CTAG = TaskContract.TaskLists.SYNC1;
|
||||||
|
|
||||||
@Override protected Uri entriesURI() { return syncAdapterURI(TaskContract.Tasks.CONTENT_URI); }
|
@Override protected Uri entriesURI() { return syncAdapterURI(TaskContract.Tasks.getContentUri(TASKS_AUTHORITY)); }
|
||||||
@Override protected String entryColumnAccountType() { return TaskContract.Tasks.ACCOUNT_TYPE; }
|
@Override protected String entryColumnAccountType() { return TaskContract.Tasks.ACCOUNT_TYPE; }
|
||||||
@Override protected String entryColumnAccountName() { return TaskContract.Tasks.ACCOUNT_NAME; }
|
@Override protected String entryColumnAccountName() { return TaskContract.Tasks.ACCOUNT_NAME; }
|
||||||
@Override protected String entryColumnParentID() { return TaskContract.Tasks.LIST_ID; }
|
@Override protected String entryColumnParentID() { return TaskContract.Tasks.LIST_ID; }
|
||||||
@ -46,15 +59,16 @@ public class LocalTaskList extends LocalCollection<Task> {
|
|||||||
|
|
||||||
|
|
||||||
public static Uri create(Account account, ContentResolver resolver, ServerInfo.ResourceInfo info) throws LocalStorageException {
|
public static Uri create(Account account, ContentResolver resolver, ServerInfo.ResourceInfo info) throws LocalStorageException {
|
||||||
final ContentProviderClient client = resolver.acquireContentProviderClient(TaskContract.AUTHORITY);
|
final ContentProviderClient client = resolver.acquireContentProviderClient(TASKS_AUTHORITY);
|
||||||
if (client == null)
|
if (client == null)
|
||||||
throw new LocalStorageException("No tasks provider found");
|
throw new LocalStorageException("No tasks provider found");
|
||||||
|
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(TaskContract.TaskLists.ACCOUNT_NAME, account.name);
|
values.put(TaskContract.TaskLists.ACCOUNT_NAME, account.name);
|
||||||
values.put(TaskContract.TaskLists.ACCOUNT_TYPE, /*account.type*/"davdroid.new");
|
values.put(TaskContract.TaskLists.ACCOUNT_TYPE, account.type);
|
||||||
values.put(TaskContract.TaskLists._SYNC_ID, info.getURL());
|
values.put(TaskContract.TaskLists._SYNC_ID, info.getURL());
|
||||||
values.put(TaskContract.TaskLists.LIST_NAME, info.getTitle());
|
values.put(TaskContract.TaskLists.LIST_NAME, info.getTitle());
|
||||||
|
values.put(TaskContract.TaskLists.LIST_COLOR, DAVUtils.CalDAVtoARGBColor(info.getColor()));
|
||||||
values.put(TaskContract.TaskLists.OWNER, account.name);
|
values.put(TaskContract.TaskLists.OWNER, account.name);
|
||||||
values.put(TaskContract.TaskLists.ACCESS_LEVEL, 0);
|
values.put(TaskContract.TaskLists.ACCESS_LEVEL, 0);
|
||||||
values.put(TaskContract.TaskLists.SYNC_ENABLED, 1);
|
values.put(TaskContract.TaskLists.SYNC_ENABLED, 1);
|
||||||
@ -122,19 +136,36 @@ public class LocalTaskList extends LocalCollection<Task> {
|
|||||||
try {
|
try {
|
||||||
@Cleanup final Cursor cursor = providerClient.query(entriesURI(),
|
@Cleanup final Cursor cursor = providerClient.query(entriesURI(),
|
||||||
new String[] {
|
new String[] {
|
||||||
/* 0 */ entryColumnUID(), TaskContract.Tasks.TITLE, TaskContract.Tasks.LOCATION, TaskContract.Tasks.DESCRIPTION, TaskContract.Tasks.URL,
|
/* 0 */ entryColumnUID(), TaskContract.Tasks.TITLE, TaskContract.Tasks.LOCATION, TaskContract.Tasks.DESCRIPTION, TaskContract.Tasks.URL,
|
||||||
/* 5 */ TaskContract.Tasks.CLASSIFICATION, TaskContract.Tasks.STATUS, TaskContract.Tasks.PERCENT_COMPLETE,
|
/* 5 */ TaskContract.Tasks.CLASSIFICATION, TaskContract.Tasks.STATUS, TaskContract.Tasks.PERCENT_COMPLETE,
|
||||||
/* 8 */ TaskContract.Tasks.DTSTART, TaskContract.Tasks.IS_ALLDAY, /*TaskContract.Tasks.COMPLETED, TaskContract.Tasks.COMPLETED_IS_ALLDAY*/
|
/* 8 */ TaskContract.Tasks.TZ, TaskContract.Tasks.DTSTART, TaskContract.Tasks.IS_ALLDAY,
|
||||||
|
/* 11 */ TaskContract.Tasks.DUE, TaskContract.Tasks.DURATION, TaskContract.Tasks.COMPLETED,
|
||||||
|
/* 14 */ TaskContract.Tasks.CREATED, TaskContract.Tasks.LAST_MODIFIED, TaskContract.Tasks.PRIORITY
|
||||||
}, entryColumnID() + "=?", new String[]{ String.valueOf(record.getLocalID()) }, null);
|
}, entryColumnID() + "=?", new String[]{ String.valueOf(record.getLocalID()) }, null);
|
||||||
|
|
||||||
Task task = (Task)record;
|
Task task = (Task)record;
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
task.setUid(cursor.getString(0));
|
task.setUid(cursor.getString(0));
|
||||||
|
|
||||||
task.setSummary(cursor.getString(1));
|
if (!cursor.isNull(14))
|
||||||
task.setLocation(cursor.getString(2));
|
task.setCreatedAt(new DateTime(cursor.getLong(14)));
|
||||||
task.setDescription(cursor.getString(3));
|
if (!cursor.isNull(15))
|
||||||
task.setUrl(cursor.getString(4));
|
task.setLastModified(new DateTime(cursor.getLong(15)));
|
||||||
|
|
||||||
|
if (!StringUtils.isEmpty(cursor.getString(1)))
|
||||||
|
task.setSummary(cursor.getString(1));
|
||||||
|
|
||||||
|
if (!StringUtils.isEmpty(cursor.getString(2)))
|
||||||
|
task.setLocation(cursor.getString(2));
|
||||||
|
|
||||||
|
if (!StringUtils.isEmpty(cursor.getString(3)))
|
||||||
|
task.setDescription(cursor.getString(3));
|
||||||
|
|
||||||
|
if (!StringUtils.isEmpty(cursor.getString(4)))
|
||||||
|
task.setUrl(cursor.getString(4));
|
||||||
|
|
||||||
|
if (!cursor.isNull(16))
|
||||||
|
task.setPriority(cursor.getInt(16));
|
||||||
|
|
||||||
if (!cursor.isNull(5))
|
if (!cursor.isNull(5))
|
||||||
switch (cursor.getInt(5)) {
|
switch (cursor.getInt(5)) {
|
||||||
@ -165,17 +196,37 @@ public class LocalTaskList extends LocalCollection<Task> {
|
|||||||
if (!cursor.isNull(7))
|
if (!cursor.isNull(7))
|
||||||
task.setPercentComplete(cursor.getInt(7));
|
task.setPercentComplete(cursor.getInt(7));
|
||||||
|
|
||||||
if (!cursor.isNull(8) && !cursor.isNull(9)) {
|
TimeZone tz = null;
|
||||||
long ts = cursor.getLong(8);
|
if (!cursor.isNull(8))
|
||||||
boolean allDay = cursor.getInt(9) != 0;
|
tz = DateUtils.getTimeZone(cursor.getString(8));
|
||||||
task.setDtStart(new DtStart(allDay ? new Date(ts) : new DateTime(ts)));
|
|
||||||
|
if (!cursor.isNull(9) && !cursor.isNull(10)) {
|
||||||
|
long ts = cursor.getLong(9);
|
||||||
|
boolean allDay = cursor.getInt(10) != 0;
|
||||||
|
|
||||||
|
Date dt;
|
||||||
|
if (allDay)
|
||||||
|
dt = new Date(ts);
|
||||||
|
else {
|
||||||
|
dt = new DateTime(ts);
|
||||||
|
if (tz != null)
|
||||||
|
((DateTime)dt).setTimeZone(tz);
|
||||||
|
}
|
||||||
|
task.setDtStart(new DtStart(dt));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if (!cursor.isNull(10) && !cursor.isNull(11)) {
|
if (!cursor.isNull(11)) {
|
||||||
long ts = cursor.getLong(10);
|
DateTime dt = new DateTime(cursor.getLong(11));
|
||||||
// boolean allDay = cursor.getInt(11) != 0;
|
if (tz != null)
|
||||||
task.setCompletedAt(new Completed(allDay ? new Date(ts) : new DateTime(ts)));
|
dt.setTimeZone(tz);
|
||||||
}*/
|
task.setDue(new Due(dt));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cursor.isNull(12))
|
||||||
|
task.setDuration(new Duration(new Dur(cursor.getString(12))));
|
||||||
|
|
||||||
|
if (!cursor.isNull(13))
|
||||||
|
task.setCompletedAt(new Completed(new DateTime(cursor.getLong(13))));
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
@ -188,17 +239,21 @@ public class LocalTaskList extends LocalCollection<Task> {
|
|||||||
final Task task = (Task)resource;
|
final Task task = (Task)resource;
|
||||||
|
|
||||||
if (!update)
|
if (!update)
|
||||||
builder = builder
|
builder .withValue(entryColumnParentID(), id)
|
||||||
.withValue(entryColumnParentID(), id)
|
|
||||||
.withValue(entryColumnRemoteName(), task.getName());
|
.withValue(entryColumnRemoteName(), task.getName());
|
||||||
|
|
||||||
builder = builder
|
builder.withValue(entryColumnUID(), task.getUid())
|
||||||
.withValue(entryColumnUID(), task.getUid())
|
|
||||||
.withValue(entryColumnETag(), task.getETag())
|
.withValue(entryColumnETag(), task.getETag())
|
||||||
.withValue(TaskContract.Tasks.TITLE, task.getSummary())
|
.withValue(TaskContract.Tasks.TITLE, task.getSummary())
|
||||||
.withValue(TaskContract.Tasks.LOCATION, task.getLocation())
|
.withValue(TaskContract.Tasks.LOCATION, task.getLocation())
|
||||||
.withValue(TaskContract.Tasks.DESCRIPTION, task.getDescription())
|
.withValue(TaskContract.Tasks.DESCRIPTION, task.getDescription())
|
||||||
.withValue(TaskContract.Tasks.URL, task.getUrl());
|
.withValue(TaskContract.Tasks.URL, task.getUrl())
|
||||||
|
.withValue(TaskContract.Tasks.PRIORITY, task.getPriority());
|
||||||
|
|
||||||
|
if (task.getCreatedAt() != null)
|
||||||
|
builder.withValue(TaskContract.Tasks.CREATED, task.getCreatedAt().getTime());
|
||||||
|
if (task.getLastModified() != null)
|
||||||
|
builder.withValue(TaskContract.Tasks.LAST_MODIFIED, task.getLastModified().getTime());
|
||||||
|
|
||||||
if (task.getClassification() != null) {
|
if (task.getClassification() != null) {
|
||||||
int classCode = TaskContract.Tasks.CLASSIFICATION_PRIVATE;
|
int classCode = TaskContract.Tasks.CLASSIFICATION_PRIVATE;
|
||||||
@ -220,40 +275,54 @@ public class LocalTaskList extends LocalCollection<Task> {
|
|||||||
else if (task.getStatus() == Status.VTODO_CANCELLED)
|
else if (task.getStatus() == Status.VTODO_CANCELLED)
|
||||||
statusCode = TaskContract.Tasks.STATUS_CANCELLED;
|
statusCode = TaskContract.Tasks.STATUS_CANCELLED;
|
||||||
}
|
}
|
||||||
builder = builder
|
builder .withValue(TaskContract.Tasks.STATUS, statusCode)
|
||||||
.withValue(TaskContract.Tasks.STATUS, statusCode)
|
|
||||||
.withValue(TaskContract.Tasks.PERCENT_COMPLETE, task.getPercentComplete());
|
.withValue(TaskContract.Tasks.PERCENT_COMPLETE, task.getPercentComplete());
|
||||||
|
|
||||||
/*if (task.getCreatedAt() != null)
|
TimeZone tz = null;
|
||||||
builder = builder.withValue(TaskContract.Tasks.CREATED, task.getCreatedAt().getDate().getTime());/*
|
|
||||||
|
|
||||||
if (task.getDtStart() != null) {
|
if (task.getDtStart() != null) {
|
||||||
Date start = task.getDtStart().getDate();
|
Date start = task.getDtStart().getDate();
|
||||||
boolean allDay;
|
boolean allDay;
|
||||||
if (start instanceof DateTime)
|
if (start instanceof DateTime) {
|
||||||
allDay = false;
|
allDay = false;
|
||||||
else {
|
tz = ((DateTime)start).getTimeZone();
|
||||||
task.getDtStart().setUtc(true);
|
} else
|
||||||
allDay = true;
|
allDay = true;
|
||||||
}
|
|
||||||
long ts = start.getTime();
|
long ts = start.getTime();
|
||||||
builder = builder.withValue(TaskContract.Tasks.DTSTART, ts);
|
builder .withValue(TaskContract.Tasks.DTSTART, ts)
|
||||||
builder = builder.withValue(TaskContract.Tasks.IS_ALLDAY, allDay ? 1 : 0);
|
.withValue(TaskContract.Tasks.IS_ALLDAY, allDay ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if (task.getCompletedAt() != null) {
|
if (task.getDue() != null) {
|
||||||
|
Due due = task.getDue();
|
||||||
|
builder.withValue(TaskContract.Tasks.DUE, due.getDate().getTime());
|
||||||
|
if (tz == null)
|
||||||
|
tz = due.getTimeZone();
|
||||||
|
|
||||||
|
} else if (task.getDuration() != null)
|
||||||
|
builder.withValue(TaskContract.Tasks.DURATION, task.getDuration().getValue());
|
||||||
|
|
||||||
|
if (task.getCompletedAt() != null) {
|
||||||
Date completed = task.getCompletedAt().getDate();
|
Date completed = task.getCompletedAt().getDate();
|
||||||
boolean allDay;
|
boolean allDay;
|
||||||
if (completed instanceof DateTime)
|
if (completed instanceof DateTime) {
|
||||||
allDay = false;
|
allDay = false;
|
||||||
else {
|
if (tz == null)
|
||||||
|
tz = ((DateTime)completed).getTimeZone();
|
||||||
|
} else {
|
||||||
task.getCompletedAt().setUtc(true);
|
task.getCompletedAt().setUtc(true);
|
||||||
allDay = true;
|
allDay = true;
|
||||||
}
|
}
|
||||||
long ts = completed.getTime();
|
long ts = completed.getTime();
|
||||||
builder = builder.withValue(TaskContract.Tasks.COMPLETED, ts);
|
builder .withValue(TaskContract.Tasks.COMPLETED, ts)
|
||||||
builder = builder.withValue(TaskContract.Tasks.COMPLETED_IS_ALLDAY, allDay ? 1 : 0);
|
.withValue(TaskContract.Tasks.COMPLETED_IS_ALLDAY, allDay ? 1 : 0);
|
||||||
}*/
|
}
|
||||||
|
|
||||||
|
// TZ *must* be provided when DTSTART or DUE is set
|
||||||
|
if ((task.getDtStart() != null || task.getDue() != null) && tz == null)
|
||||||
|
tz = DateUtils.getTimeZone(TimeZones.GMT_ID);
|
||||||
|
if (tz != null)
|
||||||
|
builder.withValue(TaskContract.Tasks.TZ, DateUtils.findAndroidTimezoneID(tz.getID()));
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
@ -269,18 +338,28 @@ public class LocalTaskList extends LocalCollection<Task> {
|
|||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
|
|
||||||
|
public static boolean isAvailable(Context context) {
|
||||||
|
try {
|
||||||
|
@Cleanup("release") ContentProviderClient client = context.getContentResolver().acquireContentProviderClient(TASKS_AUTHORITY);
|
||||||
|
return client != null;
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
Log.e(TAG, "DAVdroid is not allowed to access tasks", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Uri syncAdapterURI(Uri baseURI) {
|
protected Uri syncAdapterURI(Uri baseURI) {
|
||||||
return baseURI.buildUpon()
|
return baseURI.buildUpon()
|
||||||
.appendQueryParameter(entryColumnAccountType(), /*account.type*/"davdroid.new")
|
.appendQueryParameter(entryColumnAccountType(), account.type)
|
||||||
.appendQueryParameter(entryColumnAccountName(), account.name)
|
.appendQueryParameter(entryColumnAccountName(), account.name)
|
||||||
.appendQueryParameter(TaskContract.CALLER_IS_SYNCADAPTER, "true")
|
.appendQueryParameter(TaskContract.CALLER_IS_SYNCADAPTER, "true")
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Uri taskListsURI(Account account) {
|
protected static Uri taskListsURI(Account account) {
|
||||||
return TaskContract.TaskLists.CONTENT_URI.buildUpon()
|
return TaskContract.TaskLists.getContentUri(TASKS_AUTHORITY).buildUpon()
|
||||||
.appendQueryParameter(TaskContract.TaskLists.ACCOUNT_TYPE, /*account.type*/"davdroid.new")
|
.appendQueryParameter(TaskContract.TaskLists.ACCOUNT_TYPE, account.type)
|
||||||
.appendQueryParameter(TaskContract.TaskLists.ACCOUNT_NAME, account.name)
|
.appendQueryParameter(TaskContract.TaskLists.ACCOUNT_NAME, account.name)
|
||||||
.appendQueryParameter(TaskContract.CALLER_IS_SYNCADAPTER, "true")
|
.appendQueryParameter(TaskContract.CALLER_IS_SYNCADAPTER, "true")
|
||||||
.build();
|
.build();
|
||||||
|
@ -19,9 +19,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
|
|
||||||
@RequiredArgsConstructor(suppressConstructorProperties=true)
|
@RequiredArgsConstructor(suppressConstructorProperties=true)
|
||||||
@Data
|
@Data
|
||||||
public class ServerInfo implements Serializable {
|
public class ServerInfo {
|
||||||
private static final long serialVersionUID = 6744847358282980437L;
|
|
||||||
|
|
||||||
enum Scheme {
|
enum Scheme {
|
||||||
HTTP, HTTPS, MAILTO
|
HTTP, HTTPS, MAILTO
|
||||||
}
|
}
|
||||||
@ -34,8 +32,9 @@ public class ServerInfo implements Serializable {
|
|||||||
|
|
||||||
private boolean calDAV = false, cardDAV = false;
|
private boolean calDAV = false, cardDAV = false;
|
||||||
private List<ResourceInfo>
|
private List<ResourceInfo>
|
||||||
addressBooks = new LinkedList<ResourceInfo>(),
|
addressBooks = new LinkedList<>(),
|
||||||
calendars = new LinkedList<ResourceInfo>();
|
calendars = new LinkedList<>(),
|
||||||
|
todoLists = new LinkedList<>();
|
||||||
|
|
||||||
|
|
||||||
public boolean hasEnabledCalendars() {
|
public boolean hasEnabledCalendars() {
|
||||||
@ -48,9 +47,7 @@ public class ServerInfo implements Serializable {
|
|||||||
|
|
||||||
@RequiredArgsConstructor(suppressConstructorProperties=true)
|
@RequiredArgsConstructor(suppressConstructorProperties=true)
|
||||||
@Data
|
@Data
|
||||||
public static class ResourceInfo implements Serializable {
|
public static class ResourceInfo {
|
||||||
private static final long serialVersionUID = -5516934508229552112L;
|
|
||||||
|
|
||||||
public enum Type {
|
public enum Type {
|
||||||
ADDRESS_BOOK,
|
ADDRESS_BOOK,
|
||||||
CALENDAR
|
CALENDAR
|
||||||
@ -69,9 +66,25 @@ public class ServerInfo implements Serializable {
|
|||||||
VCardVersion vCardVersion;
|
VCardVersion vCardVersion;
|
||||||
|
|
||||||
String timezone;
|
String timezone;
|
||||||
boolean supportingEvents = false,
|
|
||||||
supportingNotes = false,
|
|
||||||
supportingTasks = false;
|
// copy constructor
|
||||||
|
public ResourceInfo(ResourceInfo src) {
|
||||||
|
enabled = src.enabled;
|
||||||
|
type = src.type;
|
||||||
|
readOnly = src.readOnly;
|
||||||
|
|
||||||
|
URL = src.URL;
|
||||||
|
title = src.title;
|
||||||
|
description = src.description;
|
||||||
|
color = src.color;
|
||||||
|
|
||||||
|
vCardVersion = src.vCardVersion;
|
||||||
|
timezone = src.timezone;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// some logic
|
||||||
|
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
if (title == null) {
|
if (title == null) {
|
||||||
|
@ -7,6 +7,8 @@ import net.fortuna.ical4j.data.CalendarOutputter;
|
|||||||
import net.fortuna.ical4j.data.ParserException;
|
import net.fortuna.ical4j.data.ParserException;
|
||||||
import net.fortuna.ical4j.model.Component;
|
import net.fortuna.ical4j.model.Component;
|
||||||
import net.fortuna.ical4j.model.ComponentList;
|
import net.fortuna.ical4j.model.ComponentList;
|
||||||
|
import net.fortuna.ical4j.model.Date;
|
||||||
|
import net.fortuna.ical4j.model.DateTime;
|
||||||
import net.fortuna.ical4j.model.PropertyList;
|
import net.fortuna.ical4j.model.PropertyList;
|
||||||
import net.fortuna.ical4j.model.ValidationException;
|
import net.fortuna.ical4j.model.ValidationException;
|
||||||
import net.fortuna.ical4j.model.component.VToDo;
|
import net.fortuna.ical4j.model.component.VToDo;
|
||||||
@ -15,6 +17,9 @@ import net.fortuna.ical4j.model.property.Completed;
|
|||||||
import net.fortuna.ical4j.model.property.Created;
|
import net.fortuna.ical4j.model.property.Created;
|
||||||
import net.fortuna.ical4j.model.property.Description;
|
import net.fortuna.ical4j.model.property.Description;
|
||||||
import net.fortuna.ical4j.model.property.DtStart;
|
import net.fortuna.ical4j.model.property.DtStart;
|
||||||
|
import net.fortuna.ical4j.model.property.Due;
|
||||||
|
import net.fortuna.ical4j.model.property.Duration;
|
||||||
|
import net.fortuna.ical4j.model.property.LastModified;
|
||||||
import net.fortuna.ical4j.model.property.Location;
|
import net.fortuna.ical4j.model.property.Location;
|
||||||
import net.fortuna.ical4j.model.property.PercentComplete;
|
import net.fortuna.ical4j.model.property.PercentComplete;
|
||||||
import net.fortuna.ical4j.model.property.Priority;
|
import net.fortuna.ical4j.model.property.Priority;
|
||||||
@ -41,13 +46,17 @@ import lombok.Setter;
|
|||||||
public class Task extends Resource {
|
public class Task extends Resource {
|
||||||
private final static String TAG = "davdroid.Task";
|
private final static String TAG = "davdroid.Task";
|
||||||
|
|
||||||
|
@Getter @Setter DateTime createdAt;
|
||||||
|
@Getter @Setter DateTime lastModified;
|
||||||
|
|
||||||
@Getter @Setter String summary, location, description, url;
|
@Getter @Setter String summary, location, description, url;
|
||||||
@Getter @Setter int priority;
|
@Getter @Setter int priority;
|
||||||
@Getter @Setter Clazz classification;
|
@Getter @Setter Clazz classification;
|
||||||
@Getter @Setter Status status;
|
@Getter @Setter Status status;
|
||||||
|
|
||||||
@Getter @Setter Created createdAt;
|
|
||||||
@Getter @Setter DtStart dtStart;
|
@Getter @Setter DtStart dtStart;
|
||||||
|
@Getter @Setter Due due;
|
||||||
|
@Getter @Setter Duration duration;
|
||||||
@Getter @Setter Completed completedAt;
|
@Getter @Setter Completed completedAt;
|
||||||
@Getter @Setter Integer percentComplete;
|
@Getter @Setter Integer percentComplete;
|
||||||
|
|
||||||
@ -90,6 +99,11 @@ public class Task extends Resource {
|
|||||||
if (todo.getUid() != null)
|
if (todo.getUid() != null)
|
||||||
uid = todo.getUid().getValue();
|
uid = todo.getUid().getValue();
|
||||||
|
|
||||||
|
if (todo.getCreated() != null)
|
||||||
|
createdAt = todo.getCreated().getDateTime();
|
||||||
|
if (todo.getLastModified() != null)
|
||||||
|
lastModified = todo.getLastModified().getDateTime();
|
||||||
|
|
||||||
if (todo.getSummary() != null)
|
if (todo.getSummary() != null)
|
||||||
summary = todo.getSummary().getValue();
|
summary = todo.getSummary().getValue();
|
||||||
if (todo.getLocation() != null)
|
if (todo.getLocation() != null)
|
||||||
@ -105,8 +119,10 @@ public class Task extends Resource {
|
|||||||
if (todo.getStatus() != null)
|
if (todo.getStatus() != null)
|
||||||
status = todo.getStatus();
|
status = todo.getStatus();
|
||||||
|
|
||||||
if (todo.getCreated() != null)
|
if (todo.getDue() != null)
|
||||||
createdAt = todo.getCreated();
|
due = todo.getDue();
|
||||||
|
if (todo.getDuration() != null)
|
||||||
|
duration = todo.getDuration();
|
||||||
if (todo.getStartDate() != null)
|
if (todo.getStartDate() != null)
|
||||||
dtStart = todo.getStartDate();
|
dtStart = todo.getStartDate();
|
||||||
if (todo.getDateCompleted() != null)
|
if (todo.getDateCompleted() != null)
|
||||||
@ -134,6 +150,11 @@ public class Task extends Resource {
|
|||||||
if (uid != null)
|
if (uid != null)
|
||||||
props.add(new Uid(uid));
|
props.add(new Uid(uid));
|
||||||
|
|
||||||
|
if (createdAt != null)
|
||||||
|
props.add(new Created(createdAt));
|
||||||
|
if (lastModified != null)
|
||||||
|
props.add(new LastModified(lastModified));
|
||||||
|
|
||||||
if (summary != null)
|
if (summary != null)
|
||||||
props.add(new Summary(summary));
|
props.add(new Summary(summary));
|
||||||
if (location != null)
|
if (location != null)
|
||||||
@ -153,8 +174,10 @@ public class Task extends Resource {
|
|||||||
if (status != null)
|
if (status != null)
|
||||||
props.add(status);
|
props.add(status);
|
||||||
|
|
||||||
if (createdAt != null)
|
if (due != null)
|
||||||
props.add(createdAt);
|
props.add(due);
|
||||||
|
if (duration != null)
|
||||||
|
props.add(duration);
|
||||||
if (dtStart != null)
|
if (dtStart != null)
|
||||||
props.add(dtStart);
|
props.add(dtStart);
|
||||||
if (completedAt != null)
|
if (completedAt != null)
|
||||||
|
@ -102,12 +102,12 @@ public class AccountSettings {
|
|||||||
|
|
||||||
// sync. settings
|
// sync. settings
|
||||||
|
|
||||||
public Long getContactsSyncInterval() {
|
public Long getSyncInterval(String authority) {
|
||||||
if (ContentResolver.getIsSyncable(account, ContactsContract.AUTHORITY) <= 0)
|
if (ContentResolver.getIsSyncable(account, authority) <= 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (ContentResolver.getSyncAutomatically(account, ContactsContract.AUTHORITY)) {
|
if (ContentResolver.getSyncAutomatically(account, authority)) {
|
||||||
List<PeriodicSync> syncs = ContentResolver.getPeriodicSyncs(account, ContactsContract.AUTHORITY);
|
List<PeriodicSync> syncs = ContentResolver.getPeriodicSyncs(account, authority);
|
||||||
if (syncs.isEmpty())
|
if (syncs.isEmpty())
|
||||||
return SYNC_INTERVAL_MANUALLY;
|
return SYNC_INTERVAL_MANUALLY;
|
||||||
else
|
else
|
||||||
@ -116,35 +116,12 @@ public class AccountSettings {
|
|||||||
return SYNC_INTERVAL_MANUALLY;
|
return SYNC_INTERVAL_MANUALLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContactsSyncInterval(long seconds) {
|
public void setSyncInterval(String authority, long seconds) {
|
||||||
if (seconds == SYNC_INTERVAL_MANUALLY) {
|
if (seconds == SYNC_INTERVAL_MANUALLY) {
|
||||||
ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, false);
|
ContentResolver.setSyncAutomatically(account, authority, false);
|
||||||
} else {
|
} else {
|
||||||
ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true);
|
ContentResolver.setSyncAutomatically(account, authority, true);
|
||||||
ContentResolver.addPeriodicSync(account, ContactsContract.AUTHORITY, new Bundle(), seconds);
|
ContentResolver.addPeriodicSync(account, authority, new Bundle(), seconds);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getCalendarsSyncInterval() {
|
|
||||||
if (ContentResolver.getIsSyncable(account, CalendarContract.AUTHORITY) <= 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (ContentResolver.getSyncAutomatically(account, CalendarContract.AUTHORITY)) {
|
|
||||||
List<PeriodicSync> syncs = ContentResolver.getPeriodicSyncs(account, CalendarContract.AUTHORITY);
|
|
||||||
if (syncs.isEmpty())
|
|
||||||
return SYNC_INTERVAL_MANUALLY;
|
|
||||||
else
|
|
||||||
return syncs.get(0).period;
|
|
||||||
} else
|
|
||||||
return SYNC_INTERVAL_MANUALLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCalendarsSyncInterval(long seconds) {
|
|
||||||
if (seconds == SYNC_INTERVAL_MANUALLY) {
|
|
||||||
ContentResolver.setSyncAutomatically(account, CalendarContract.AUTHORITY, false);
|
|
||||||
} else {
|
|
||||||
ContentResolver.setSyncAutomatically(account, CalendarContract.AUTHORITY, true);
|
|
||||||
ContentResolver.addPeriodicSync(account, CalendarContract.AUTHORITY, new Bundle(), seconds);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
package at.bitfire.davdroid.syncadapter;
|
|
||||||
|
|
||||||
import android.accounts.Account;
|
|
||||||
import android.app.Service;
|
|
||||||
import android.content.ContentProviderClient;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import at.bitfire.davdroid.resource.CalDavNotebook;
|
|
||||||
import at.bitfire.davdroid.resource.LocalCollection;
|
|
||||||
import at.bitfire.davdroid.resource.LocalNotebook;
|
|
||||||
import at.bitfire.davdroid.resource.RemoteCollection;
|
|
||||||
|
|
||||||
public class NotesSyncAdapterService extends Service {
|
|
||||||
private static NotesSyncAdapter syncAdapter;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate() {
|
|
||||||
if (syncAdapter == null)
|
|
||||||
syncAdapter = new NotesSyncAdapter(getApplicationContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
syncAdapter.close();
|
|
||||||
syncAdapter = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IBinder onBind(Intent intent) {
|
|
||||||
return syncAdapter.getSyncAdapterBinder();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static class NotesSyncAdapter extends DavSyncAdapter {
|
|
||||||
private final static String TAG = "davdroid.NotesSync";
|
|
||||||
|
|
||||||
private NotesSyncAdapter(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Map<LocalCollection<?>, RemoteCollection<?>> getSyncPairs(Account account, ContentProviderClient provider) {
|
|
||||||
AccountSettings settings = new AccountSettings(getContext(), account);
|
|
||||||
String userName = settings.getUserName(),
|
|
||||||
password = settings.getPassword();
|
|
||||||
boolean preemptive = settings.getPreemptiveAuth();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Map<LocalCollection<?>, RemoteCollection<?>> map = new HashMap<LocalCollection<?>, RemoteCollection<?>>();
|
|
||||||
|
|
||||||
for (LocalNotebook noteList : LocalNotebook.findAll(account, provider)) {
|
|
||||||
RemoteCollection<?> dav = new CalDavNotebook(httpClient, noteList.getUrl(), userName, password, preemptive);
|
|
||||||
map.put(noteList, dav);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
} catch (RemoteException ex) {
|
|
||||||
Log.e(TAG, "Couldn't find local notebooks", ex);
|
|
||||||
} catch (URISyntaxException ex) {
|
|
||||||
Log.e(TAG, "Couldn't build calendar URI", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,9 +20,7 @@ import java.net.URISyntaxException;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import at.bitfire.davdroid.resource.CalDavCalendar;
|
|
||||||
import at.bitfire.davdroid.resource.CalDavTaskList;
|
import at.bitfire.davdroid.resource.CalDavTaskList;
|
||||||
import at.bitfire.davdroid.resource.LocalCalendar;
|
|
||||||
import at.bitfire.davdroid.resource.LocalCollection;
|
import at.bitfire.davdroid.resource.LocalCollection;
|
||||||
import at.bitfire.davdroid.resource.LocalTaskList;
|
import at.bitfire.davdroid.resource.LocalTaskList;
|
||||||
import at.bitfire.davdroid.resource.RemoteCollection;
|
import at.bitfire.davdroid.resource.RemoteCollection;
|
||||||
|
@ -17,8 +17,13 @@ import android.preference.ListPreference;
|
|||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceFragment;
|
import android.preference.PreferenceFragment;
|
||||||
import android.preference.SwitchPreference;
|
import android.preference.SwitchPreference;
|
||||||
|
import android.provider.CalendarContract;
|
||||||
|
import android.provider.ContactsContract;
|
||||||
|
|
||||||
|
import org.dmfs.provider.tasks.TaskContract;
|
||||||
|
|
||||||
import at.bitfire.davdroid.R;
|
import at.bitfire.davdroid.R;
|
||||||
|
import at.bitfire.davdroid.resource.LocalTaskList;
|
||||||
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
||||||
import ezvcard.VCardVersion;
|
import ezvcard.VCardVersion;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@ -78,7 +83,7 @@ public class AccountFragment extends PreferenceFragment {
|
|||||||
|
|
||||||
// category: synchronization
|
// category: synchronization
|
||||||
final ListPreference prefSyncContacts = (ListPreference)findPreference("sync_interval_contacts");
|
final ListPreference prefSyncContacts = (ListPreference)findPreference("sync_interval_contacts");
|
||||||
final Long syncIntervalContacts = settings.getContactsSyncInterval();
|
final Long syncIntervalContacts = settings.getSyncInterval(ContactsContract.AUTHORITY);
|
||||||
if (syncIntervalContacts != null) {
|
if (syncIntervalContacts != null) {
|
||||||
prefSyncContacts.setValue(syncIntervalContacts.toString());
|
prefSyncContacts.setValue(syncIntervalContacts.toString());
|
||||||
if (syncIntervalContacts == AccountSettings.SYNC_INTERVAL_MANUALLY)
|
if (syncIntervalContacts == AccountSettings.SYNC_INTERVAL_MANUALLY)
|
||||||
@ -88,7 +93,7 @@ public class AccountFragment extends PreferenceFragment {
|
|||||||
prefSyncContacts.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
prefSyncContacts.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
settings.setContactsSyncInterval(Long.parseLong((String)newValue));
|
settings.setSyncInterval(ContactsContract.AUTHORITY, Long.parseLong((String) newValue));
|
||||||
readFromAccount();
|
readFromAccount();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -99,7 +104,7 @@ public class AccountFragment extends PreferenceFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final ListPreference prefSyncCalendars = (ListPreference)findPreference("sync_interval_calendars");
|
final ListPreference prefSyncCalendars = (ListPreference)findPreference("sync_interval_calendars");
|
||||||
final Long syncIntervalCalendars = settings.getCalendarsSyncInterval();
|
final Long syncIntervalCalendars = settings.getSyncInterval(CalendarContract.AUTHORITY);
|
||||||
if (syncIntervalCalendars != null) {
|
if (syncIntervalCalendars != null) {
|
||||||
prefSyncCalendars.setValue(syncIntervalCalendars.toString());
|
prefSyncCalendars.setValue(syncIntervalCalendars.toString());
|
||||||
if (syncIntervalCalendars == AccountSettings.SYNC_INTERVAL_MANUALLY)
|
if (syncIntervalCalendars == AccountSettings.SYNC_INTERVAL_MANUALLY)
|
||||||
@ -109,7 +114,7 @@ public class AccountFragment extends PreferenceFragment {
|
|||||||
prefSyncCalendars.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
prefSyncCalendars.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
settings.setCalendarsSyncInterval(Long.parseLong((String)newValue));
|
settings.setSyncInterval(CalendarContract.AUTHORITY, Long.parseLong((String) newValue));
|
||||||
readFromAccount();
|
readFromAccount();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -119,6 +124,27 @@ public class AccountFragment extends PreferenceFragment {
|
|||||||
prefSyncCalendars.setSummary(R.string.settings_sync_summary_not_available);
|
prefSyncCalendars.setSummary(R.string.settings_sync_summary_not_available);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final ListPreference prefSyncTasks = (ListPreference)findPreference("sync_interval_tasks");
|
||||||
|
final Long syncIntervalTasks = settings.getSyncInterval(LocalTaskList.TASKS_AUTHORITY);
|
||||||
|
if (syncIntervalTasks != null) {
|
||||||
|
prefSyncTasks.setValue(syncIntervalTasks.toString());
|
||||||
|
if (syncIntervalTasks == AccountSettings.SYNC_INTERVAL_MANUALLY)
|
||||||
|
prefSyncTasks.setSummary(R.string.settings_sync_summary_manually);
|
||||||
|
else
|
||||||
|
prefSyncTasks.setSummary(getString(R.string.settings_sync_summary_periodically, syncIntervalTasks / 60));
|
||||||
|
prefSyncTasks.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
settings.setSyncInterval(LocalTaskList.TASKS_AUTHORITY, Long.parseLong((String) newValue));
|
||||||
|
readFromAccount();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
prefSyncTasks.setEnabled(false);
|
||||||
|
prefSyncTasks.setSummary(R.string.settings_sync_summary_not_available);
|
||||||
|
}
|
||||||
|
|
||||||
// category: address book
|
// category: address book
|
||||||
final CheckBoxPreference prefVCard4 = (CheckBoxPreference) findPreference("vcard4_support");
|
final CheckBoxPreference prefVCard4 = (CheckBoxPreference) findPreference("vcard4_support");
|
||||||
if (settings.getAddressBookURL() != null) { // does this account even have an address book?
|
if (settings.getAddressBookURL() != null) { // does this account even have an address book?
|
||||||
|
@ -16,6 +16,7 @@ import android.provider.CalendarContract;
|
|||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
@ -26,22 +27,19 @@ import android.widget.EditText;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.dmfs.provider.tasks.TaskContract;
|
import java.util.List;
|
||||||
|
|
||||||
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.LocalCalendar;
|
import at.bitfire.davdroid.resource.LocalCalendar;
|
||||||
import at.bitfire.davdroid.resource.LocalNotebook;
|
|
||||||
import at.bitfire.davdroid.resource.LocalStorageException;
|
import at.bitfire.davdroid.resource.LocalStorageException;
|
||||||
import at.bitfire.davdroid.resource.LocalTaskList;
|
import at.bitfire.davdroid.resource.LocalTaskList;
|
||||||
import at.bitfire.davdroid.resource.ServerInfo;
|
import at.bitfire.davdroid.resource.ServerInfo;
|
||||||
import at.bitfire.davdroid.resource.Task;
|
|
||||||
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
import at.bitfire.davdroid.syncadapter.AccountSettings;
|
||||||
import at.bitfire.notebooks.provider.NoteContract;
|
|
||||||
|
|
||||||
public class AccountDetailsFragment extends Fragment implements TextWatcher {
|
public class AccountDetailsFragment extends Fragment implements TextWatcher {
|
||||||
public static final String KEY_SERVER_INFO = "server_info";
|
public static final String TAG = "davdroid.AccountDetails";
|
||||||
|
|
||||||
ServerInfo serverInfo;
|
ServerInfo serverInfo;
|
||||||
|
|
||||||
EditText editAccountName;
|
EditText editAccountName;
|
||||||
@ -51,7 +49,7 @@ public class AccountDetailsFragment extends Fragment implements TextWatcher {
|
|||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View v = inflater.inflate(R.layout.setup_account_details, container, false);
|
View v = inflater.inflate(R.layout.setup_account_details, container, false);
|
||||||
|
|
||||||
serverInfo = (ServerInfo)getArguments().getSerializable(KEY_SERVER_INFO);
|
serverInfo = ((AddAccountActivity)getActivity()).serverInfo;
|
||||||
|
|
||||||
editAccountName = (EditText)v.findViewById(R.id.account_name);
|
editAccountName = (EditText)v.findViewById(R.id.account_name);
|
||||||
editAccountName.addTextChangedListener(this);
|
editAccountName.addTextChangedListener(this);
|
||||||
@ -87,81 +85,59 @@ public class AccountDetailsFragment extends Fragment implements TextWatcher {
|
|||||||
// actions
|
// actions
|
||||||
|
|
||||||
void addAccount() {
|
void addAccount() {
|
||||||
ServerInfo serverInfo = (ServerInfo)getArguments().getSerializable(KEY_SERVER_INFO);
|
|
||||||
String accountName = editAccountName.getText().toString();
|
String accountName = editAccountName.getText().toString();
|
||||||
|
|
||||||
AccountManager accountManager = AccountManager.get(getActivity());
|
AccountManager accountManager = AccountManager.get(getActivity());
|
||||||
Account account = new Account(accountName, Constants.ACCOUNT_TYPE);
|
Account account = new Account(accountName, Constants.ACCOUNT_TYPE);
|
||||||
Bundle userData = AccountSettings.createBundle(serverInfo);
|
Bundle userData = AccountSettings.createBundle(serverInfo);
|
||||||
|
|
||||||
boolean syncContacts = false;
|
|
||||||
for (ServerInfo.ResourceInfo addressBook : serverInfo.getAddressBooks())
|
|
||||||
if (addressBook.isEnabled()) {
|
|
||||||
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 1);
|
|
||||||
syncContacts = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (syncContacts) {
|
|
||||||
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 1);
|
|
||||||
ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true);
|
|
||||||
} else
|
|
||||||
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 0);
|
|
||||||
|
|
||||||
if (accountManager.addAccountExplicitly(account, serverInfo.getPassword(), userData)) {
|
if (accountManager.addAccountExplicitly(account, serverInfo.getPassword(), userData)) {
|
||||||
// account created, now create calendars ...
|
addSync(account, ContactsContract.AUTHORITY, serverInfo.getAddressBooks(), null);
|
||||||
boolean syncCalendars = false;
|
|
||||||
for (ServerInfo.ResourceInfo calendar : serverInfo.getCalendars())
|
|
||||||
if (calendar.isEnabled() && calendar.isSupportingEvents())
|
|
||||||
try {
|
|
||||||
LocalCalendar.create(account, getActivity().getContentResolver(), calendar);
|
|
||||||
syncCalendars = true;
|
|
||||||
} catch (LocalStorageException e) {
|
|
||||||
Toast.makeText(getActivity(), "Couldn't create calendar: " + e.getMessage(), Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
if (syncCalendars) {
|
|
||||||
ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, 1);
|
|
||||||
ContentResolver.setSyncAutomatically(account, CalendarContract.AUTHORITY, true);
|
|
||||||
} else
|
|
||||||
ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, 0);
|
|
||||||
|
|
||||||
// ... and notes
|
addSync(account, CalendarContract.AUTHORITY, serverInfo.getCalendars(), new AddSyncCallback() {
|
||||||
boolean syncNotes = false;
|
@Override
|
||||||
for (ServerInfo.ResourceInfo calendar : serverInfo.getCalendars())
|
public void createLocalCollection(Account account, ServerInfo.ResourceInfo calendar) throws LocalStorageException {
|
||||||
if (calendar.isEnabled() && calendar.isSupportingNotes())
|
LocalCalendar.create(account, getActivity().getContentResolver(), calendar);
|
||||||
try {
|
}
|
||||||
LocalNotebook.create(account, getActivity().getContentResolver(), calendar);
|
});
|
||||||
syncNotes = true;
|
|
||||||
} catch (LocalStorageException e) {
|
|
||||||
Toast.makeText(getActivity(), "Couldn't create notebook: " + e.getMessage(), Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
if (syncNotes) {
|
|
||||||
ContentResolver.setIsSyncable(account, NoteContract.AUTHORITY, 1);
|
|
||||||
ContentResolver.setSyncAutomatically(account, NoteContract.AUTHORITY, true);
|
|
||||||
} else
|
|
||||||
ContentResolver.setIsSyncable(account, NoteContract.AUTHORITY, 0);
|
|
||||||
|
|
||||||
// ... and tasks
|
addSync(account, LocalTaskList.TASKS_AUTHORITY, serverInfo.getTodoLists(), new AddSyncCallback() {
|
||||||
boolean syncTasks = false;
|
@Override
|
||||||
for (ServerInfo.ResourceInfo calendar : serverInfo.getCalendars())
|
public void createLocalCollection(Account account, ServerInfo.ResourceInfo todoList) throws LocalStorageException {
|
||||||
if (calendar.isEnabled() && calendar.isSupportingTasks())
|
LocalTaskList.create(account, getActivity().getContentResolver(), todoList);
|
||||||
try {
|
}
|
||||||
LocalTaskList.create(account, getActivity().getContentResolver(), calendar);
|
});
|
||||||
syncTasks = true;
|
|
||||||
} catch (LocalStorageException e) {
|
|
||||||
Toast.makeText(getActivity(), "Couldn't create task list: " + e.getMessage(), Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
if (syncTasks) {
|
|
||||||
ContentResolver.setIsSyncable(account, TaskContract.AUTHORITY, 1);
|
|
||||||
ContentResolver.setSyncAutomatically(account, TaskContract.AUTHORITY, true);
|
|
||||||
} else
|
|
||||||
ContentResolver.setIsSyncable(account, TaskContract.AUTHORITY, 0);
|
|
||||||
|
|
||||||
getActivity().finish();
|
getActivity().finish();
|
||||||
} else
|
} else
|
||||||
Toast.makeText(getActivity(), "Couldn't create account (account with this name already existing?)", Toast.LENGTH_LONG).show();
|
Toast.makeText(getActivity(), "Couldn't create account (account with this name already existing?)", Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected interface AddSyncCallback {
|
||||||
|
void createLocalCollection(Account account, ServerInfo.ResourceInfo resource) throws LocalStorageException;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addSync(Account account, String authority, List<ServerInfo.ResourceInfo> resourceList, AddSyncCallback callback) {
|
||||||
|
boolean sync = false;
|
||||||
|
for (ServerInfo.ResourceInfo resource : resourceList)
|
||||||
|
if (resource.isEnabled()) {
|
||||||
|
sync = true;
|
||||||
|
if (callback != null)
|
||||||
|
try {
|
||||||
|
callback.createLocalCollection(account, resource);
|
||||||
|
} catch(LocalStorageException e) {
|
||||||
|
Log.e(TAG, "Couldn't add sync collection", e);
|
||||||
|
Toast.makeText(getActivity(), "Couldn't set up synchronization for " + authority, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sync) {
|
||||||
|
ContentResolver.setIsSyncable(account, authority, 1);
|
||||||
|
ContentResolver.setSyncAutomatically(account, authority, true);
|
||||||
|
} else
|
||||||
|
ContentResolver.setIsSyncable(account, authority, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// input validation
|
// input validation
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -14,12 +14,17 @@ import android.os.Bundle;
|
|||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import at.bitfire.davdroid.Constants;
|
import at.bitfire.davdroid.Constants;
|
||||||
import at.bitfire.davdroid.R;
|
import at.bitfire.davdroid.R;
|
||||||
|
import at.bitfire.davdroid.resource.ServerInfo;
|
||||||
|
|
||||||
public class AddAccountActivity extends Activity {
|
public class AddAccountActivity extends Activity {
|
||||||
|
|
||||||
|
protected ServerInfo serverInfo;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@ -40,6 +45,11 @@ public class AddAccountActivity extends Activity {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void installTasksApp(View view) {
|
||||||
|
final Intent intent = new Intent(Intent.ACTION_VIEW).setData(Uri.parse("market://details?id=org.dmfs.tasks"));
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
public void showHelp(MenuItem item) {
|
public void showHelp(MenuItem item) {
|
||||||
startActivityForResult(new Intent(Intent.ACTION_VIEW, Uri.parse(Constants.WEB_URL_HELP)), 0);
|
startActivityForResult(new Intent(Intent.ACTION_VIEW, Uri.parse(Constants.WEB_URL_HELP)), 0);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013 – 2015 Ricki Hirner (bitfire web engineering).
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v3.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/gpl.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
package at.bitfire.davdroid.ui.setup;
|
||||||
|
|
||||||
|
import android.app.DialogFragment;
|
||||||
|
import android.app.Fragment;
|
||||||
|
import android.app.FragmentManager;
|
||||||
|
import android.app.FragmentTransaction;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import at.bitfire.davdroid.R;
|
||||||
|
import at.bitfire.davdroid.resource.LocalTaskList;
|
||||||
|
|
||||||
|
public class InstallAppsFragment extends Fragment implements Runnable {
|
||||||
|
private static final String TAG = "davdroid.setup";
|
||||||
|
|
||||||
|
final protected Handler timerHandler = new Handler();
|
||||||
|
|
||||||
|
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View v = inflater.inflate(R.layout.setup_install_apps, container, false);
|
||||||
|
setHasOptionsMenu(true);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
|
inflater.inflate(R.menu.only_skip, menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
timerHandler.postDelayed(this, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
timerHandler.removeCallbacks(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case R.id.skip:
|
||||||
|
skip(true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (LocalTaskList.isAvailable(getActivity()))
|
||||||
|
skip(false);
|
||||||
|
else
|
||||||
|
timerHandler.postDelayed(this, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void skip(boolean addToBackStack) {
|
||||||
|
FragmentManager fm = getFragmentManager();
|
||||||
|
|
||||||
|
if (!addToBackStack)
|
||||||
|
fm.popBackStack();
|
||||||
|
|
||||||
|
getFragmentManager().beginTransaction()
|
||||||
|
.replace(R.id.right_pane, new SelectCollectionsFragment())
|
||||||
|
.addToBackStack(null)
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -8,6 +8,7 @@
|
|||||||
package at.bitfire.davdroid.ui.setup;
|
package at.bitfire.davdroid.ui.setup;
|
||||||
|
|
||||||
import android.app.DialogFragment;
|
import android.app.DialogFragment;
|
||||||
|
import android.app.Fragment;
|
||||||
import android.app.LoaderManager.LoaderCallbacks;
|
import android.app.LoaderManager.LoaderCallbacks;
|
||||||
import android.content.AsyncTaskLoader;
|
import android.content.AsyncTaskLoader;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -30,12 +31,13 @@ import java.security.cert.CertPathValidatorException;
|
|||||||
|
|
||||||
import at.bitfire.davdroid.R;
|
import at.bitfire.davdroid.R;
|
||||||
import at.bitfire.davdroid.resource.DavResourceFinder;
|
import at.bitfire.davdroid.resource.DavResourceFinder;
|
||||||
|
import at.bitfire.davdroid.resource.LocalTaskList;
|
||||||
import at.bitfire.davdroid.resource.ServerInfo;
|
import at.bitfire.davdroid.resource.ServerInfo;
|
||||||
import at.bitfire.davdroid.webdav.DavException;
|
import at.bitfire.davdroid.webdav.DavException;
|
||||||
import lombok.Cleanup;
|
import lombok.Cleanup;
|
||||||
|
|
||||||
public class QueryServerDialogFragment extends DialogFragment implements LoaderCallbacks<ServerInfo> {
|
public class QueryServerDialogFragment extends DialogFragment implements LoaderCallbacks<ServerInfo> {
|
||||||
private static final String TAG = "davdroid.QueryServerDialogFragment";
|
private static final String TAG = "davdroid.QueryServer";
|
||||||
public static final String
|
public static final String
|
||||||
EXTRA_BASE_URI = "base_uri",
|
EXTRA_BASE_URI = "base_uri",
|
||||||
EXTRA_USER_NAME = "user_name",
|
EXTRA_USER_NAME = "user_name",
|
||||||
@ -71,13 +73,16 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC
|
|||||||
if (serverInfo.getErrorMessage() != null)
|
if (serverInfo.getErrorMessage() != null)
|
||||||
Toast.makeText(getActivity(), serverInfo.getErrorMessage(), Toast.LENGTH_LONG).show();
|
Toast.makeText(getActivity(), serverInfo.getErrorMessage(), Toast.LENGTH_LONG).show();
|
||||||
else {
|
else {
|
||||||
SelectCollectionsFragment selectCollections = new SelectCollectionsFragment();
|
((AddAccountActivity)getActivity()).serverInfo = serverInfo;
|
||||||
Bundle arguments = new Bundle();
|
|
||||||
arguments.putSerializable(SelectCollectionsFragment.KEY_SERVER_INFO, serverInfo);
|
Fragment nextFragment;
|
||||||
selectCollections.setArguments(arguments);
|
if (!serverInfo.getTodoLists().isEmpty() && !LocalTaskList.isAvailable(getActivity()))
|
||||||
|
nextFragment = new InstallAppsFragment();
|
||||||
|
else
|
||||||
|
nextFragment = new SelectCollectionsFragment();
|
||||||
|
|
||||||
getFragmentManager().beginTransaction()
|
getFragmentManager().beginTransaction()
|
||||||
.replace(R.id.right_pane, selectCollections)
|
.replace(R.id.right_pane, nextFragment)
|
||||||
.addToBackStack(null)
|
.addToBackStack(null)
|
||||||
.commitAllowingStateLoss();
|
.commitAllowingStateLoss();
|
||||||
}
|
}
|
||||||
|
@ -18,28 +18,50 @@ import android.widget.CheckedTextView;
|
|||||||
import android.widget.ListAdapter;
|
import android.widget.ListAdapter;
|
||||||
|
|
||||||
import at.bitfire.davdroid.R;
|
import at.bitfire.davdroid.R;
|
||||||
|
import at.bitfire.davdroid.resource.LocalTaskList;
|
||||||
import at.bitfire.davdroid.resource.ServerInfo;
|
import at.bitfire.davdroid.resource.ServerInfo;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Order of display:
|
||||||
|
*
|
||||||
|
* number of rows type
|
||||||
|
* nAddressBookHeadings (0 or 1) heading: "address books"
|
||||||
|
* nAddressBooks address book info
|
||||||
|
* nCalendarHeadings (0 or 1) heading: "calendars"
|
||||||
|
* nCalendars calendar info
|
||||||
|
* nNotebookHeadings (0 or 1) heading: "notebooks"
|
||||||
|
* nNotebooks notebook info
|
||||||
|
* nTaskListHeadings (0 or 1) heading: "task lists"
|
||||||
|
* nTaskLists task list info
|
||||||
|
*/
|
||||||
public class SelectCollectionsAdapter extends BaseAdapter implements ListAdapter {
|
public class SelectCollectionsAdapter extends BaseAdapter implements ListAdapter {
|
||||||
final static int TYPE_ADDRESS_BOOKS_HEADING = 0,
|
final static int
|
||||||
TYPE_ADDRESS_BOOKS_ROW = 1,
|
TYPE_ADDRESS_BOOKS_HEADING = 0,
|
||||||
TYPE_CALENDARS_HEADING = 2,
|
TYPE_ADDRESS_BOOKS_ROW = 1,
|
||||||
TYPE_CALENDARS_ROW = 3;
|
TYPE_CALENDARS_HEADING = 2,
|
||||||
|
TYPE_CALENDARS_ROW = 3,
|
||||||
|
TYPE_TASK_LISTS_HEADING = 4,
|
||||||
|
TYPE_TASK_LISTS_ROW = 5;
|
||||||
|
|
||||||
protected Context context;
|
protected Context context;
|
||||||
protected ServerInfo serverInfo;
|
protected ServerInfo serverInfo;
|
||||||
@Getter protected int nAddressBooks, nAddressbookHeadings, nCalendars, nCalendarHeadings;
|
@Getter protected int
|
||||||
|
nAddressBooks, nAddressBookHeadings,
|
||||||
|
nCalendars, nCalendarHeadings,
|
||||||
|
nTaskLists, nTaskListHeadings;
|
||||||
|
|
||||||
|
|
||||||
public SelectCollectionsAdapter(Context context, ServerInfo serverInfo) {
|
public SelectCollectionsAdapter(Context context, ServerInfo serverInfo) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
|
||||||
this.serverInfo = serverInfo;
|
this.serverInfo = serverInfo;
|
||||||
nAddressBooks = (serverInfo.getAddressBooks() == null) ? 0 : serverInfo.getAddressBooks().size();
|
nAddressBooks = serverInfo.getAddressBooks() == null ? 0 : serverInfo.getAddressBooks().size();
|
||||||
nAddressbookHeadings = (nAddressBooks == 0) ? 0 : 1;
|
nAddressBookHeadings = nAddressBooks == 0 ? 0 : 1;
|
||||||
nCalendars = (serverInfo.getCalendars() == null) ? 0 : serverInfo.getCalendars().size();
|
nCalendars = serverInfo.getCalendars() == null ? 0 : serverInfo.getCalendars().size();
|
||||||
nCalendarHeadings = (nCalendars == 0) ? 0 : 1;
|
nCalendarHeadings = nCalendars == 0 ? 0 : 1;
|
||||||
|
nTaskLists = serverInfo.getTodoLists() == null ? 0 : serverInfo.getTodoLists().size();
|
||||||
|
nTaskListHeadings = nTaskLists == 0 ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -47,17 +69,23 @@ public class SelectCollectionsAdapter extends BaseAdapter implements ListAdapter
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return nAddressbookHeadings + nAddressBooks + nCalendarHeadings + nCalendars;
|
return nAddressBookHeadings + nAddressBooks + nCalendarHeadings + nCalendars + nTaskListHeadings + nTaskLists;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getItem(int position) {
|
public Object getItem(int position) {
|
||||||
if (position >= nAddressbookHeadings &&
|
if (position >= nAddressBookHeadings &&
|
||||||
position < (nAddressbookHeadings + nAddressBooks))
|
position < (nAddressBookHeadings + nAddressBooks))
|
||||||
return serverInfo.getAddressBooks().get(position - nAddressbookHeadings);
|
return serverInfo.getAddressBooks().get(position - nAddressBookHeadings);
|
||||||
else if (position >= (nAddressbookHeadings + nAddressBooks + nCalendarHeadings) &&
|
|
||||||
(position < (nAddressbookHeadings + nAddressBooks + nCalendarHeadings + nCalendars)))
|
else if (position >= (nAddressBookHeadings + nAddressBooks + nCalendarHeadings) &&
|
||||||
return serverInfo.getCalendars().get(position - (nAddressbookHeadings + nAddressBooks + nCalendarHeadings));
|
(position < (nAddressBookHeadings + nAddressBooks + nCalendarHeadings + nCalendars)))
|
||||||
|
return serverInfo.getCalendars().get(position - (nAddressBookHeadings + nAddressBooks + nCalendarHeadings));
|
||||||
|
|
||||||
|
else if (position >= (nAddressBookHeadings + nAddressBooks + nCalendarHeadings + nCalendars + nTaskListHeadings) &&
|
||||||
|
(position < (nAddressBookHeadings + nAddressBooks + nCalendarHeadings + nCalendars + + nTaskListHeadings + nTaskLists)))
|
||||||
|
return serverInfo.getTodoLists().get(position - (nAddressBookHeadings + nAddressBooks + nCalendarHeadings + nCalendars + nTaskListHeadings));
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,19 +104,26 @@ public class SelectCollectionsAdapter extends BaseAdapter implements ListAdapter
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getViewTypeCount() {
|
public int getViewTypeCount() {
|
||||||
return 4;
|
return TYPE_TASK_LISTS_ROW + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemViewType(int position) {
|
public int getItemViewType(int position) {
|
||||||
if ((nAddressbookHeadings != 0) && (position == 0))
|
if ((nAddressBookHeadings != 0) && (position == 0))
|
||||||
return TYPE_ADDRESS_BOOKS_HEADING;
|
return TYPE_ADDRESS_BOOKS_HEADING;
|
||||||
else if ((nAddressbookHeadings != 0) && (position > 0) && (position < nAddressbookHeadings + nAddressBooks))
|
else if ((nAddressBooks != 0) && (position > 0) && (position < nAddressBookHeadings + nAddressBooks))
|
||||||
return TYPE_ADDRESS_BOOKS_ROW;
|
return TYPE_ADDRESS_BOOKS_ROW;
|
||||||
else if ((nCalendars != 0) && (position == nAddressbookHeadings + nAddressBooks))
|
|
||||||
|
else if ((nCalendarHeadings != 0) && (position == nAddressBookHeadings + nAddressBooks))
|
||||||
return TYPE_CALENDARS_HEADING;
|
return TYPE_CALENDARS_HEADING;
|
||||||
else if ((nCalendars != 0) && (position > nAddressbookHeadings + nAddressBooks) && (position < nAddressbookHeadings + nAddressBooks + nCalendarHeadings + nCalendars))
|
else if ((nCalendars != 0) && (position > nAddressBookHeadings + nAddressBooks) && (position < nAddressBookHeadings + nAddressBooks + nCalendarHeadings + nCalendars))
|
||||||
return TYPE_CALENDARS_ROW;
|
return TYPE_CALENDARS_ROW;
|
||||||
|
|
||||||
|
else if ((nTaskListHeadings != 0) && (position == nAddressBookHeadings + nAddressBooks + nCalendarHeadings + nCalendars))
|
||||||
|
return TYPE_TASK_LISTS_HEADING;
|
||||||
|
else if ((nTaskLists != 0) && (position > nAddressBookHeadings + nAddressBooks + nCalendarHeadings + nCalendars) && (position < nAddressBookHeadings + nAddressBooks + nCalendarHeadings + nCalendars + nTaskListHeadings + nTaskLists))
|
||||||
|
return TYPE_TASK_LISTS_ROW;
|
||||||
|
|
||||||
else
|
else
|
||||||
return IGNORE_ITEM_VIEW_TYPE;
|
return IGNORE_ITEM_VIEW_TYPE;
|
||||||
}
|
}
|
||||||
@ -97,11 +132,13 @@ public class SelectCollectionsAdapter extends BaseAdapter implements ListAdapter
|
|||||||
@SuppressLint("InflateParams")
|
@SuppressLint("InflateParams")
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
View v = convertView;
|
View v = convertView;
|
||||||
|
|
||||||
|
int viewType = getItemViewType(position);
|
||||||
|
|
||||||
// step 1: get view (either by creating or recycling)
|
// step 1: get view (either by creating or recycling)
|
||||||
if (v == null) {
|
if (v == null) {
|
||||||
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||||
switch (getItemViewType(position)) {
|
switch (viewType) {
|
||||||
case TYPE_ADDRESS_BOOKS_HEADING:
|
case TYPE_ADDRESS_BOOKS_HEADING:
|
||||||
v = inflater.inflate(R.layout.setup_address_books_heading, parent, false);
|
v = inflater.inflate(R.layout.setup_address_books_heading, parent, false);
|
||||||
break;
|
break;
|
||||||
@ -112,21 +149,38 @@ public class SelectCollectionsAdapter extends BaseAdapter implements ListAdapter
|
|||||||
case TYPE_CALENDARS_HEADING:
|
case TYPE_CALENDARS_HEADING:
|
||||||
v = inflater.inflate(R.layout.setup_calendars_heading, parent, false);
|
v = inflater.inflate(R.layout.setup_calendars_heading, parent, false);
|
||||||
break;
|
break;
|
||||||
|
case TYPE_TASK_LISTS_HEADING:
|
||||||
|
v = inflater.inflate(R.layout.setup_task_lists_heading, parent, false);
|
||||||
|
break;
|
||||||
case TYPE_CALENDARS_ROW:
|
case TYPE_CALENDARS_ROW:
|
||||||
|
case TYPE_TASK_LISTS_ROW:
|
||||||
v = inflater.inflate(android.R.layout.simple_list_item_multiple_choice, null);
|
v = inflater.inflate(android.R.layout.simple_list_item_multiple_choice, null);
|
||||||
v.setPadding(0, 8, 0, 8);
|
v.setPadding(0, 8, 0, 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// step 2: fill view with content
|
// step 2: fill view with content
|
||||||
switch (getItemViewType(position)) {
|
switch (viewType) {
|
||||||
case TYPE_ADDRESS_BOOKS_ROW:
|
case TYPE_ADDRESS_BOOKS_ROW:
|
||||||
setContent((CheckedTextView)v, R.drawable.addressbook, (ServerInfo.ResourceInfo)getItem(position));
|
setContent((CheckedTextView)v, R.drawable.addressbook, (ServerInfo.ResourceInfo)getItem(position));
|
||||||
break;
|
break;
|
||||||
case TYPE_CALENDARS_ROW:
|
case TYPE_CALENDARS_ROW:
|
||||||
setContent((CheckedTextView)v, R.drawable.calendar, (ServerInfo.ResourceInfo)getItem(position));
|
case TYPE_TASK_LISTS_ROW:
|
||||||
|
setContent((CheckedTextView)v, R.drawable.calendar, (ServerInfo.ResourceInfo) getItem(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// disable task list selection if there's no local task provider
|
||||||
|
if (viewType == TYPE_TASK_LISTS_ROW && !LocalTaskList.isAvailable(context)) {
|
||||||
|
final CheckedTextView check = (CheckedTextView)v;
|
||||||
|
check.setEnabled(false);
|
||||||
|
check.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
check.setChecked(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +210,6 @@ public class SelectCollectionsAdapter extends BaseAdapter implements ListAdapter
|
|||||||
@Override
|
@Override
|
||||||
public boolean isEnabled(int position) {
|
public boolean isEnabled(int position) {
|
||||||
int type = getItemViewType(position);
|
int type = getItemViewType(position);
|
||||||
return (type == TYPE_ADDRESS_BOOKS_ROW || type == TYPE_CALENDARS_ROW);
|
return (type == TYPE_ADDRESS_BOOKS_ROW || type == TYPE_CALENDARS_ROW || type == TYPE_TASK_LISTS_ROW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,13 +24,17 @@ import at.bitfire.davdroid.R;
|
|||||||
import at.bitfire.davdroid.resource.ServerInfo;
|
import at.bitfire.davdroid.resource.ServerInfo;
|
||||||
|
|
||||||
public class SelectCollectionsFragment extends ListFragment {
|
public class SelectCollectionsFragment extends ListFragment {
|
||||||
public static final String KEY_SERVER_INFO = "server_info";
|
|
||||||
|
protected ServerInfo serverInfo;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
serverInfo = ((AddAccountActivity)getActivity()).serverInfo;
|
||||||
|
|
||||||
View v = super.onCreateView(inflater, container, savedInstanceState);
|
View v = super.onCreateView(inflater, container, savedInstanceState);
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +54,6 @@ public class SelectCollectionsFragment extends ListFragment {
|
|||||||
View header = getActivity().getLayoutInflater().inflate(R.layout.setup_select_collections_header, getListView(), false);
|
View header = getActivity().getLayoutInflater().inflate(R.layout.setup_select_collections_header, getListView(), false);
|
||||||
listView.addHeaderView(header, getListView(), false);
|
listView.addHeaderView(header, getListView(), false);
|
||||||
|
|
||||||
final ServerInfo serverInfo = (ServerInfo)getArguments().getSerializable(KEY_SERVER_INFO);
|
|
||||||
final SelectCollectionsAdapter adapter = new SelectCollectionsAdapter(view.getContext(), serverInfo);
|
final SelectCollectionsAdapter adapter = new SelectCollectionsAdapter(view.getContext(), serverInfo);
|
||||||
setListAdapter(adapter);
|
setListAdapter(adapter);
|
||||||
|
|
||||||
@ -80,13 +83,13 @@ public class SelectCollectionsFragment extends ListFragment {
|
|||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.next:
|
case R.id.next:
|
||||||
ServerInfo serverInfo = (ServerInfo)getArguments().getSerializable(KEY_SERVER_INFO);
|
|
||||||
|
|
||||||
// synchronize only selected collections
|
// synchronize only selected collections
|
||||||
for (ServerInfo.ResourceInfo addressBook : serverInfo.getAddressBooks())
|
for (ServerInfo.ResourceInfo addressBook : serverInfo.getAddressBooks())
|
||||||
addressBook.setEnabled(false);
|
addressBook.setEnabled(false);
|
||||||
for (ServerInfo.ResourceInfo calendar : serverInfo.getCalendars())
|
for (ServerInfo.ResourceInfo calendar : serverInfo.getCalendars())
|
||||||
calendar.setEnabled(false);
|
calendar.setEnabled(false);
|
||||||
|
for (ServerInfo.ResourceInfo todoList : serverInfo.getTodoLists())
|
||||||
|
todoList.setEnabled(false);
|
||||||
|
|
||||||
ListAdapter adapter = getListView().getAdapter();
|
ListAdapter adapter = getListView().getAdapter();
|
||||||
for (long id : getListView().getCheckedItemIds()) {
|
for (long id : getListView().getCheckedItemIds()) {
|
||||||
@ -95,14 +98,8 @@ public class SelectCollectionsFragment extends ListFragment {
|
|||||||
info.setEnabled(true);
|
info.setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pass to "account details" fragment
|
|
||||||
AccountDetailsFragment accountDetails = new AccountDetailsFragment();
|
|
||||||
Bundle arguments = new Bundle();
|
|
||||||
arguments.putSerializable(SelectCollectionsFragment.KEY_SERVER_INFO, serverInfo);
|
|
||||||
accountDetails.setArguments(arguments);
|
|
||||||
|
|
||||||
getFragmentManager().beginTransaction()
|
getFragmentManager().beginTransaction()
|
||||||
.replace(R.id.right_pane, accountDetails)
|
.replace(R.id.right_pane, new AccountDetailsFragment())
|
||||||
.addToBackStack(null)
|
.addToBackStack(null)
|
||||||
.commitAllowingStateLoss();
|
.commitAllowingStateLoss();
|
||||||
break;
|
break;
|
||||||
|
@ -1 +0,0 @@
|
|||||||
../../../../../../../../../notebooks/app/src/main/java/at/bitfire/notebooks/provider/NoteContract.java
|
|
File diff suppressed because it is too large
Load Diff
1
app/src/main/java/org/dmfs/provider/tasks/TaskContract.java
Symbolic link
1
app/src/main/java/org/dmfs/provider/tasks/TaskContract.java
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
/home/rfc2822/Entwicklung/Android/task-provider/src/org/dmfs/provider/tasks/TaskContract.java
|
1
app/src/main/java/org/dmfs/provider/tasks/UriFactory.java
Symbolic link
1
app/src/main/java/org/dmfs/provider/tasks/UriFactory.java
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
/home/rfc2822/Entwicklung/Android/task-provider/src/org/dmfs/provider/tasks/UriFactory.java
|
BIN
app/src/main/res/drawable-hdpi/navigation_skip.png
Normal file
BIN
app/src/main/res/drawable-hdpi/navigation_skip.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 661 B |
BIN
app/src/main/res/drawable-mdpi/navigation_skip.png
Normal file
BIN
app/src/main/res/drawable-mdpi/navigation_skip.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 488 B |
BIN
app/src/main/res/drawable-xhdpi/navigation_skip.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/navigation_skip.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 813 B |
BIN
app/src/main/res/drawable-xxhdpi/navigation_skip.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/navigation_skip.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
29
app/src/main/res/layout-sw720dp/setup_task_lists_heading.xml
Normal file
29
app/src/main/res/layout-sw720dp/setup_task_lists_heading.xml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (c) 2013 – 2015 Ricki Hirner (bitfire web engineering).
|
||||||
|
~ All rights reserved. This program and the accompanying materials
|
||||||
|
~ are made available under the terms of the GNU Public License v3.0
|
||||||
|
~ which accompanies this distribution, and is available at
|
||||||
|
~ http://www.gnu.org/licenses/gpl.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/TextView.Heading"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:text="@string/setup_task_lists" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="@string/setup_select_task_lists" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
45
app/src/main/res/layout/setup_install_apps.xml
Normal file
45
app/src/main/res/layout/setup_install_apps.xml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (c) 2013 – 2015 Ricki Hirner (bitfire web engineering).
|
||||||
|
~ All rights reserved. This program and the accompanying materials
|
||||||
|
~ are made available under the terms of the GNU Public License v3.0
|
||||||
|
~ which accompanies this distribution, and is available at
|
||||||
|
~ http://www.gnu.org/licenses/gpl.html
|
||||||
|
-->
|
||||||
|
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="20dp"
|
||||||
|
tools:context=".MainActivity" >
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:text="@string/setup_install_apps_info"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:text="@string/setup_install_tasks_app_info"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/setup_install_tasks_app"
|
||||||
|
android:onClick="installTasksApp"
|
||||||
|
android:layout_gravity="center_horizontal"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
@ -1,3 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
<!--
|
||||||
~ Copyright (c) 2013 – 2015 Ricki Hirner (bitfire web engineering).
|
~ Copyright (c) 2013 – 2015 Ricki Hirner (bitfire web engineering).
|
||||||
~ All rights reserved. This program and the accompanying materials
|
~ All rights reserved. This program and the accompanying materials
|
||||||
@ -6,10 +7,13 @@
|
|||||||
~ http://www.gnu.org/licenses/gpl.html
|
~ http://www.gnu.org/licenses/gpl.html
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
android:accountType="bitfire.at.davdroid"
|
|
||||||
android:contentAuthority="at.bitfire.notebooks.provider"
|
<item
|
||||||
android:allowParallelSyncs="true"
|
android:id="@+id/skip"
|
||||||
android:supportsUploading="true"
|
android:icon="@drawable/navigation_skip"
|
||||||
android:isAlwaysSyncable="true"
|
android:showAsAction="always|withText"
|
||||||
android:userVisible="true" />
|
android:title="@string/skip">
|
||||||
|
</item>
|
||||||
|
|
||||||
|
</menu>
|
@ -11,6 +11,7 @@
|
|||||||
<!-- common strings -->
|
<!-- common strings -->
|
||||||
<string name="app_name">DAVdroid</string>
|
<string name="app_name">DAVdroid</string>
|
||||||
<string name="next">Weiter</string>
|
<string name="next">Weiter</string>
|
||||||
|
<string name="skip">Überspringen</string>
|
||||||
<string name="help">Hilfe</string>
|
<string name="help">Hilfe</string>
|
||||||
|
|
||||||
<string name="exception_cert_path_validation">Nicht vertrauenswürdiges Zertifikat in der Zertifikatskette (siehe FAQ)</string>
|
<string name="exception_cert_path_validation">Nicht vertrauenswürdiges Zertifikat in der Zertifikatskette (siehe FAQ)</string>
|
||||||
@ -127,6 +128,7 @@
|
|||||||
<string name="settings_sync_summary_periodically">Alle %d Minuten + sofort bei lokalen Änderungen</string>
|
<string name="settings_sync_summary_periodically">Alle %d Minuten + sofort bei lokalen Änderungen</string>
|
||||||
<string name="settings_sync_summary_not_available">Nicht verfügbar</string>
|
<string name="settings_sync_summary_not_available">Nicht verfügbar</string>
|
||||||
<string name="settings_sync_interval_calendars">Häufigkeit der Kalender-Synchronisierung</string>
|
<string name="settings_sync_interval_calendars">Häufigkeit der Kalender-Synchronisierung</string>
|
||||||
|
<string name="settings_sync_interval_tasks">Häufigkeit der Aufgaben-Synchronisierung</string>
|
||||||
<string-array name="settings_sync_interval_names">
|
<string-array name="settings_sync_interval_names">
|
||||||
<item>Nur manuell</item>
|
<item>Nur manuell</item>
|
||||||
<item>Alle 5 Minuten</item>
|
<item>Alle 5 Minuten</item>
|
||||||
@ -146,11 +148,18 @@
|
|||||||
<string name="setup_neither_caldav_nor_carddav">An dieser Adresse konnte kein CalDAV- oder CardDAV-Dienst gefunden werden.</string>
|
<string name="setup_neither_caldav_nor_carddav">An dieser Adresse konnte kein CalDAV- oder CardDAV-Dienst gefunden werden.</string>
|
||||||
<string name="setup_add_account">Konto hinzufügen</string>
|
<string name="setup_add_account">Konto hinzufügen</string>
|
||||||
<string name="setup_querying_server">Daten werden vom Server abgefragt. Bitte warten…</string>
|
<string name="setup_querying_server">Daten werden vom Server abgefragt. Bitte warten…</string>
|
||||||
|
<string name="setup_install_apps_info">Android bietet im Gegensatz zu Kontakten und Terminen keine integrierte Lösung für Aufgaben.</string>
|
||||||
|
<string name="setup_install_tasks_app_info">DAVdroid kann mit der "Aufgaben"-App von Marten Gajda synchronisieren. Sie können diese App installieren, um Aufgaben zu synchronisieren, oder auf Aufgaben verzichten und die Installation überspringen.</string>
|
||||||
|
<string name="setup_install_tasks_app">Aufgaben-App installieren</string>
|
||||||
<string name="setup_what_to_sync">Welche Ordner sollen synchronisiert werden?</string>
|
<string name="setup_what_to_sync">Welche Ordner sollen synchronisiert werden?</string>
|
||||||
<string name="setup_address_books">Adressbücher</string>
|
<string name="setup_address_books">Adressbücher</string>
|
||||||
<string name="setup_calendars">Kalender</string>
|
<string name="setup_calendars">Kalender</string>
|
||||||
|
<string name="setup_notebooks">Notizbücher</string>
|
||||||
|
<string name="setup_task_lists">Aufgabenlisten</string>
|
||||||
<string name="setup_select_address_book">Ein oder kein Adressbuch auswählen (nochmal berühren, um abzuwählen):</string>
|
<string name="setup_select_address_book">Ein oder kein Adressbuch auswählen (nochmal berühren, um abzuwählen):</string>
|
||||||
<string name="setup_select_calendars">Kalender zur Synchronisation auswählen:</string>
|
<string name="setup_select_calendars">Kalender zur Synchronisation auswählen:</string>
|
||||||
|
<string name="setup_select_notebooks">Notizbücher zur Synchronisation auswählen:</string>
|
||||||
|
<string name="setup_select_task_lists">Aufgabenlisten zur Synchronisation auswählen:</string>
|
||||||
|
|
||||||
<string name="setup_account_details">Konto-Details</string>
|
<string name="setup_account_details">Konto-Details</string>
|
||||||
<string name="setup_account_name">Kontoname:</string>
|
<string name="setup_account_name">Kontoname:</string>
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
<!-- common strings -->
|
<!-- common strings -->
|
||||||
<string name="app_name">DAVdroid</string>
|
<string name="app_name">DAVdroid</string>
|
||||||
<string name="next">Next</string>
|
<string name="next">Next</string>
|
||||||
|
<string name="skip">Skip</string>
|
||||||
<string name="help">Help</string>
|
<string name="help">Help</string>
|
||||||
|
|
||||||
<string name="exception_cert_path_validation">Untrusted certificate in certificate path. See FAQ for more info.</string>
|
<string name="exception_cert_path_validation">Untrusted certificate in certificate path. See FAQ for more info.</string>
|
||||||
@ -131,6 +132,7 @@
|
|||||||
<string name="settings_sync_summary_periodically">Every %d minutes + immediately on local changes</string>
|
<string name="settings_sync_summary_periodically">Every %d minutes + immediately on local changes</string>
|
||||||
<string name="settings_sync_summary_not_available">Not available</string>
|
<string name="settings_sync_summary_not_available">Not available</string>
|
||||||
<string name="settings_sync_interval_calendars">Calendars sync. interval</string>
|
<string name="settings_sync_interval_calendars">Calendars sync. interval</string>
|
||||||
|
<string name="settings_sync_interval_tasks">Tasks sync. interval</string>
|
||||||
<string-array name="settings_sync_interval_seconds">
|
<string-array name="settings_sync_interval_seconds">
|
||||||
<item>-1</item>
|
<item>-1</item>
|
||||||
<item>300</item>
|
<item>300</item>
|
||||||
@ -160,11 +162,16 @@
|
|||||||
<string name="setup_neither_caldav_nor_carddav">No CalDAV-/CardDAV service is available at this location.</string>
|
<string name="setup_neither_caldav_nor_carddav">No CalDAV-/CardDAV service is available at this location.</string>
|
||||||
<string name="setup_add_account">Add account</string>
|
<string name="setup_add_account">Add account</string>
|
||||||
<string name="setup_querying_server">Querying server. Please wait…</string>
|
<string name="setup_querying_server">Querying server. Please wait…</string>
|
||||||
|
<string name="setup_install_apps_info">Plain Android doesn\'t support to-do lists (in contrast to contacts and calendars).</string>
|
||||||
|
<string name="setup_install_tasks_app_info">DAVdroid is able to synchronize tasks with the "Tasks" app (by Marten Gajda). You may install this app if you want tasks to be synchronized or skip the installation.</string>
|
||||||
|
<string name="setup_install_tasks_app">Install Tasks app</string>
|
||||||
<string name="setup_what_to_sync">Which collections shall be synchronized?</string>
|
<string name="setup_what_to_sync">Which collections shall be synchronized?</string>
|
||||||
<string name="setup_address_books">Address books</string>
|
<string name="setup_address_books">Address books</string>
|
||||||
<string name="setup_calendars">Calendars</string>
|
<string name="setup_calendars">Calendars</string>
|
||||||
<string name="setup_select_address_book">Select up to one address book (tap again to unselect):</string>
|
<string name="setup_task_lists">Task lists</string>
|
||||||
<string name="setup_select_calendars">Select your calendars:</string>
|
<string name="setup_select_address_book">Select up to one address book (tap again to unselect) for synchronization:</string>
|
||||||
|
<string name="setup_select_calendars">Select calendars for synchronization:</string>
|
||||||
|
<string name="setup_select_task_lists">Select task lists for synchronization:</string>
|
||||||
|
|
||||||
<string name="setup_account_details">Account details</string>
|
<string name="setup_account_details">Account details</string>
|
||||||
<string name="setup_account_name">Account name:</string>
|
<string name="setup_account_name">Account name:</string>
|
||||||
|
@ -50,6 +50,13 @@
|
|||||||
android:entries="@array/settings_sync_interval_names"
|
android:entries="@array/settings_sync_interval_names"
|
||||||
android:entryValues="@array/settings_sync_interval_seconds" />
|
android:entryValues="@array/settings_sync_interval_seconds" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:key="sync_interval_tasks"
|
||||||
|
android:persistent="false"
|
||||||
|
android:title="@string/settings_sync_interval_tasks"
|
||||||
|
android:entries="@array/settings_sync_interval_names"
|
||||||
|
android:entryValues="@array/settings_sync_interval_seconds" />
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/settings_carddav">
|
<PreferenceCategory android:title="@string/settings_carddav">
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
|
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:accountType="bitfire.at.davdroid"
|
android:accountType="bitfire.at.davdroid"
|
||||||
android:contentAuthority="de.azapps.mirakel.provider"
|
android:contentAuthority="org.dmfs.tasks"
|
||||||
android:allowParallelSyncs="true"
|
android:allowParallelSyncs="true"
|
||||||
android:supportsUploading="true"
|
android:supportsUploading="true"
|
||||||
android:isAlwaysSyncable="true"
|
android:isAlwaysSyncable="true"
|
||||||
|
Loading…
Reference in New Issue
Block a user