diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 5bea0eea..3ef7fdf3 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="17" + android:versionName="0.4.4-alpha" > + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/menu/account_details.xml b/res/menu/account_details.xml new file mode 100644 index 00000000..f1ddc560 --- /dev/null +++ b/res/menu/account_details.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/res/menu/select_collections.xml b/res/menu/select_collections.xml index bf3e4d44..bd075ce5 100644 --- a/res/menu/select_collections.xml +++ b/res/menu/select_collections.xml @@ -1,11 +1,11 @@ - - - + - - + + + + \ No newline at end of file diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 4b8f4207..6a46cb32 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -75,5 +75,11 @@ * Simple XML Serialization (Apache License, Version 2.0)
* Project Lombok (MIT License)

]]> + Konto-Details + Kontoname: + Mein CalDAV/CardDAV-Konto + Email-Adresse: + "ORGANIZER der von Ihnen angelegten Termine; notwendig für Teilnehmer-Info" + "Verwenden Sie Ihre Email-Addresse als Kontoname, da Android den Kontonamen als ORGANIZER-Feld in Terminen benutzt. Sie können keine zwei Konten mit dem gleichen Namen anlegen. \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index aa80e353..c46da07d 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -83,5 +83,11 @@ * Simple XML Serialization (Apache License, Version 2.0)
* Project Lombok (MIT License)

]]> + Account details + Account name: + My CalDAV/CardDAV Account + Email address: + "ORGANIZER of your events; required if you use attendee info" + "Use your email address as account name because Android will use the account name as ORGANIZER field for events you create. You can't have two accounts with the same name. diff --git a/src/at/bitfire/davdroid/Constants.java b/src/at/bitfire/davdroid/Constants.java index 44cf5276..ff5c7324 100644 --- a/src/at/bitfire/davdroid/Constants.java +++ b/src/at/bitfire/davdroid/Constants.java @@ -9,7 +9,7 @@ package at.bitfire.davdroid; public class Constants { public static final String - APP_VERSION = "0.4.3-alpha", + APP_VERSION = "0.4.4-alpha", ACCOUNT_TYPE = "bitfire.at.davdroid", diff --git a/src/at/bitfire/davdroid/resource/Event.java b/src/at/bitfire/davdroid/resource/Event.java index b3102544..6f746912 100644 --- a/src/at/bitfire/davdroid/resource/Event.java +++ b/src/at/bitfire/davdroid/resource/Event.java @@ -50,12 +50,13 @@ import net.fortuna.ical4j.model.property.RDate; import net.fortuna.ical4j.model.property.RRule; import net.fortuna.ical4j.model.property.Status; import net.fortuna.ical4j.model.property.Summary; +import net.fortuna.ical4j.model.property.Transp; import net.fortuna.ical4j.model.property.Uid; import net.fortuna.ical4j.model.property.Version; -import net.fortuna.ical4j.util.UidGenerator; import android.text.format.Time; import android.util.Log; import at.bitfire.davdroid.Constants; +import at.bitfire.davdroid.syncadapter.DavSyncAdapter; public class Event extends Resource { @@ -76,6 +77,7 @@ public class Event extends Resource { @Getter @Setter private Boolean forPublic; @Getter @Setter private Status status; + @Getter @Setter private boolean opaque; @Getter @Setter private Organizer organizer; @Getter private List attendees = new LinkedList(); @@ -122,8 +124,7 @@ public class Event extends Resource { uid = event.getUid().getValue(); else { Log.w(TAG, "Received VEVENT without UID, generating new one"); - UidGenerator uidGenerator = new UidGenerator(Integer.toString(android.os.Process.myPid())); - uid = uidGenerator.generateUid().getValue(); + uid = DavSyncAdapter.generateUID(); } dtStart = event.getStartDate(); validateTimeZone(dtStart); @@ -144,6 +145,10 @@ public class Event extends Resource { status = event.getStatus(); + opaque = true; + if (event.getTransparency() == Transp.TRANSPARENT) + opaque = false; + organizer = event.getOrganizer(); for (Object o : event.getProperties(Property.ATTENDEE)) attendees.add((Attendee)o); @@ -196,6 +201,8 @@ public class Event extends Resource { if (status != null) props.add(status); + if (!opaque) + props.add(Transp.TRANSPARENT); if (organizer != null) props.add(organizer); diff --git a/src/at/bitfire/davdroid/resource/LocalCalendar.java b/src/at/bitfire/davdroid/resource/LocalCalendar.java index 7e5a82d8..5bb10672 100644 --- a/src/at/bitfire/davdroid/resource/LocalCalendar.java +++ b/src/at/bitfire/davdroid/resource/LocalCalendar.java @@ -7,6 +7,7 @@ ******************************************************************************/ package at.bitfire.davdroid.resource; +import java.net.URI; import java.net.URISyntaxException; import java.text.ParseException; import java.util.Date; @@ -120,7 +121,10 @@ public class LocalCalendar extends LocalCollection { values.put(Calendars.CALENDAR_COLOR, color); values.put(Calendars.CALENDAR_ACCESS_LEVEL, Calendars.CAL_ACCESS_OWNER); values.put(Calendars.ALLOWED_AVAILABILITY, Events.AVAILABILITY_BUSY + "," + Events.AVAILABILITY_FREE + "," + Events.AVAILABILITY_TENTATIVE); - values.put(Calendars.ALLOWED_ATTENDEE_TYPES, Attendees.TYPE_NONE + "," + Attendees.TYPE_REQUIRED + "," + Attendees.TYPE_OPTIONAL + "," + Attendees.TYPE_RESOURCE); + values.put(Calendars.ALLOWED_ATTENDEE_TYPES, Attendees.TYPE_NONE + "," + Attendees.TYPE_OPTIONAL + "," + Attendees.TYPE_REQUIRED + "," + Attendees.TYPE_RESOURCE); + values.put(Calendars.ALLOWED_REMINDERS, Reminders.METHOD_ALERT); + values.put(Calendars.CAN_ORGANIZER_RESPOND, 1); + values.put(Calendars.CAN_MODIFY_TIME_ZONE, 1); values.put(Calendars.OWNER_ACCOUNT, account.name); values.put(Calendars.SYNC_EVENTS, 1); values.put(Calendars.VISIBLE, 1); @@ -196,7 +200,7 @@ public class LocalCalendar extends LocalCollection { /* 8 */ Events.STATUS, Events.ACCESS_LEVEL, /* 10 */ Events.RRULE, Events.RDATE, Events.EXRULE, Events.EXDATE, /* 14 */ Events.HAS_ATTENDEE_DATA, Events.ORGANIZER, Events.SELF_ATTENDEE_STATUS, - /* 17 */ entryColumnUID(), Events.DURATION + /* 17 */ entryColumnUID(), Events.DURATION, Events.AVAILABILITY }, null, null, null); if (cursor != null && cursor.moveToNext()) { e.setUid(cursor.getString(17)); @@ -270,12 +274,15 @@ public class LocalCalendar extends LocalCollection { e.setStatus(Status.VEVENT_CANCELLED); } + // availability + e.setOpaque(cursor.getInt(19) != Events.AVAILABILITY_FREE); + // attendees if (cursor.getInt(14) != 0) { // has attendees try { - e.setOrganizer(new Organizer("mailto:" + cursor.getString(15))); + e.setOrganizer(new Organizer(new URI("mailto", cursor.getString(15), null))); } catch (URISyntaxException ex) { - Log.e(TAG, "Error parsing organizer URI, ignoring"); + Log.e(TAG, "Error when creating ORGANIZER URI, ignoring", ex); } Uri attendeesUri = Attendees.CONTENT_URI.buildUpon() @@ -287,7 +294,7 @@ public class LocalCalendar extends LocalCollection { }, Attendees.EVENT_ID + "=?", new String[] { String.valueOf(e.getLocalID()) }, null); while (c != null && c.moveToNext()) { try { - Attendee attendee = new Attendee("mailto:" + c.getString(0)); + Attendee attendee = new Attendee(new URI("mailto", c.getString(0), null)); ParameterList params = attendee.getParameters(); String cn = c.getString(1); @@ -314,13 +321,7 @@ public class LocalCalendar extends LocalCollection { } // status - int status = Attendees.ATTENDEE_STATUS_NONE; - if (relationship == Attendees.RELATIONSHIP_ORGANIZER) // we are organizer - status = cursor.getInt(16); - else - status = c.getInt(4); - - switch (status) { + switch (c.getInt(4)) { case Attendees.ATTENDEE_STATUS_INVITED: params.add(PartStat.NEEDS_ACTION); break; @@ -337,7 +338,7 @@ public class LocalCalendar extends LocalCollection { e.addAttendee(attendee); } catch (URISyntaxException ex) { - Log.e(TAG, "Couldn't parse attendee member URI, ignoring member"); + Log.e(TAG, "Couldn't parse attendee information, ignoring", ex); } } } @@ -429,7 +430,10 @@ public class LocalCalendar extends LocalCollection { .withValue(Events.ALL_DAY, event.isAllDay() ? 1 : 0) .withValue(Events.DTSTART, event.getDtStartInMillis()) .withValue(Events.EVENT_TIMEZONE, event.getDtStartTzID()) - .withValue(Events.HAS_ATTENDEE_DATA, event.getAttendees().isEmpty() ? 0 : 1); + .withValue(Events.HAS_ATTENDEE_DATA, event.getAttendees().isEmpty() ? 0 : 1) + .withValue(Events.GUESTS_CAN_INVITE_OTHERS, 1) + .withValue(Events.GUESTS_CAN_MODIFY, 1) + .withValue(Events.GUESTS_CAN_SEE_GUESTS, 1); boolean recurring = false; if (event.getRrule() != null) { @@ -478,6 +482,12 @@ public class LocalCalendar extends LocalCollection { if (event.getDescription() != null) builder = builder.withValue(Events.DESCRIPTION, event.getDescription()); + if (event.getOrganizer() != null && event.getOrganizer().getCalAddress() != null) { + URI organizer = event.getOrganizer().getCalAddress(); + if (organizer.getScheme().equalsIgnoreCase("mailto")) + builder = builder.withValue(Events.ORGANIZER, organizer.getSchemeSpecificPart()); + } + Status status = event.getStatus(); if (status != null) { int statusCode = Events.STATUS_TENTATIVE; @@ -488,6 +498,8 @@ public class LocalCalendar extends LocalCollection { builder = builder.withValue(Events.STATUS, statusCode); } + builder = builder.withValue(Events.AVAILABILITY, event.isOpaque() ? Events.AVAILABILITY_BUSY : Events.AVAILABILITY_FREE); + if (event.getForPublic() != null) builder = builder.withValue(Events.ACCESS_LEVEL, event.getForPublic() ? Events.ACCESS_PUBLIC : Events.ACCESS_PRIVATE); @@ -547,7 +559,7 @@ public class LocalCalendar extends LocalCollection { int status = Attendees.ATTENDEE_STATUS_NONE; PartStat partStat = (PartStat)attendee.getParameter(Parameter.PARTSTAT); - if (partStat == PartStat.NEEDS_ACTION) + if (partStat == null || partStat == PartStat.NEEDS_ACTION) status = Attendees.ATTENDEE_STATUS_INVITED; else if (partStat == PartStat.ACCEPTED) status = Attendees.ATTENDEE_STATUS_ACCEPTED; diff --git a/src/at/bitfire/davdroid/resource/LocalCollection.java b/src/at/bitfire/davdroid/resource/LocalCollection.java index 8dd99b3e..6ba23b0d 100644 --- a/src/at/bitfire/davdroid/resource/LocalCollection.java +++ b/src/at/bitfire/davdroid/resource/LocalCollection.java @@ -9,7 +9,6 @@ package at.bitfire.davdroid.resource; import java.util.ArrayList; import java.util.LinkedList; -import java.util.UUID; import net.fortuna.ical4j.model.ValidationException; import android.accounts.Account; @@ -23,6 +22,7 @@ import android.net.Uri; import android.os.RemoteException; import android.provider.CalendarContract; import android.util.Log; +import at.bitfire.davdroid.syncadapter.DavSyncAdapter; public abstract class LocalCollection { private static final String TAG = "davdroid.LocalCollection"; @@ -100,9 +100,9 @@ public abstract class LocalCollection { where, null, null); LinkedList fresh = new LinkedList(); while (cursor != null && cursor.moveToNext()) { - String uid = UUID.randomUUID().toString(), - resourceName = uid + fileExtension(); - T resource = findById(cursor.getLong(0), resourceName, null, true); //new Event(cursor.getLong(0), resourceName, null); + String uid = DavSyncAdapter.generateUID(), + resourceName = uid.replace("@", "_") + fileExtension(); + T resource = findById(cursor.getLong(0), resourceName, null, true); resource.setUid(uid); // new record: set generated resource name in database diff --git a/src/at/bitfire/davdroid/resource/Resource.java b/src/at/bitfire/davdroid/resource/Resource.java index 501702f8..c9192f5f 100644 --- a/src/at/bitfire/davdroid/resource/Resource.java +++ b/src/at/bitfire/davdroid/resource/Resource.java @@ -10,11 +10,11 @@ package at.bitfire.davdroid.resource; import java.io.IOException; import java.io.InputStream; -import net.fortuna.ical4j.data.ParserException; -import net.fortuna.ical4j.model.ValidationException; import lombok.Getter; import lombok.Setter; import lombok.ToString; +import net.fortuna.ical4j.data.ParserException; +import net.fortuna.ical4j.model.ValidationException; @ToString public abstract class Resource { diff --git a/src/at/bitfire/davdroid/syncadapter/AccountDetailsFragment.java b/src/at/bitfire/davdroid/syncadapter/AccountDetailsFragment.java new file mode 100644 index 00000000..9eda82e1 --- /dev/null +++ b/src/at/bitfire/davdroid/syncadapter/AccountDetailsFragment.java @@ -0,0 +1,143 @@ +package at.bitfire.davdroid.syncadapter; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.Fragment; +import android.content.ContentResolver; +import android.os.Bundle; +import android.os.RemoteException; +import android.provider.CalendarContract; +import android.provider.ContactsContract; +import android.text.Editable; +import android.text.TextWatcher; +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.EditText; +import android.widget.TextView; +import android.widget.Toast; +import at.bitfire.davdroid.Constants; +import at.bitfire.davdroid.R; +import at.bitfire.davdroid.resource.LocalCalendar; + +public class AccountDetailsFragment extends Fragment implements TextWatcher { + public static final String KEY_SERVER_INFO = "server_info"; + + ServerInfo serverInfo; + + EditText editAccountName; + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.account_details, container, false); + + serverInfo = (ServerInfo)getArguments().getSerializable(KEY_SERVER_INFO); + + editAccountName = (EditText)v.findViewById(R.id.account_name); + editAccountName.addTextChangedListener(this); + + TextView textAccountNameInfo = (TextView)v.findViewById(R.id.account_name_info); + if (!serverInfo.hasEnabledCalendars()) + textAccountNameInfo.setVisibility(View.GONE); + + setHasOptionsMenu(true); + return v; + } + + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.account_details, menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.add_account: + addAccount(); + break; + default: + return false; + } + return true; + } + + + // actions + + void addAccount() { + ServerInfo serverInfo = (ServerInfo)getArguments().getSerializable(KEY_SERVER_INFO); + try { + String accountName = editAccountName.getText().toString(); + + AccountManager accountManager = AccountManager.get(getActivity()); + Account account = new Account(accountName, Constants.ACCOUNT_TYPE); + Bundle userData = new Bundle(); + userData.putString(Constants.ACCOUNT_KEY_BASE_URL, serverInfo.getBaseURL()); + userData.putString(Constants.ACCOUNT_KEY_USERNAME, serverInfo.getUserName()); + userData.putString(Constants.ACCOUNT_KEY_AUTH_PREEMPTIVE, Boolean.toString(serverInfo.isAuthPreemptive())); + + boolean syncContacts = false; + for (ServerInfo.ResourceInfo addressBook : serverInfo.getAddressBooks()) + if (addressBook.isEnabled()) { + userData.putString(Constants.ACCOUNT_KEY_ADDRESSBOOK_PATH, addressBook.getPath()); + 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)) { + // account created, now create calendars + boolean syncCalendars = false; + for (ServerInfo.ResourceInfo calendar : serverInfo.getCalendars()) + if (calendar.isEnabled()) { + LocalCalendar.create(account, getActivity().getContentResolver(), calendar); + syncCalendars = true; + } + if (syncCalendars) { + ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, 1); + ContentResolver.setSyncAutomatically(account, CalendarContract.AUTHORITY, true); + } else + ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, 0); + + getActivity().finish(); + } else + Toast.makeText(getActivity(), "Couldn't create account (account with this name already existing?)", Toast.LENGTH_LONG).show(); + + } catch (RemoteException e) { + } + } + + + // input validation + + @Override + public void onPrepareOptionsMenu(Menu menu) { + boolean ok = false; + ok = editAccountName.getText().length() > 0; + MenuItem item = menu.findItem(R.id.add_account); + item.setEnabled(ok); + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + getActivity().invalidateOptionsMenu(); + } + + @Override + public void afterTextChanged(Editable s) { + } +} diff --git a/src/at/bitfire/davdroid/syncadapter/DavSyncAdapter.java b/src/at/bitfire/davdroid/syncadapter/DavSyncAdapter.java index 66e2d3f5..43db0b63 100644 --- a/src/at/bitfire/davdroid/syncadapter/DavSyncAdapter.java +++ b/src/at/bitfire/davdroid/syncadapter/DavSyncAdapter.java @@ -3,6 +3,9 @@ package at.bitfire.davdroid.syncadapter; import java.io.IOException; import java.util.Map; +import net.fortuna.ical4j.util.SimpleHostInfo; +import net.fortuna.ical4j.util.UidGenerator; + import org.apache.http.HttpException; import org.apache.http.auth.AuthenticationException; @@ -16,6 +19,7 @@ import android.content.OperationApplicationException; import android.content.SyncResult; import android.os.Bundle; import android.os.RemoteException; +import android.provider.Settings; import android.util.Log; import at.bitfire.davdroid.resource.LocalCollection; import at.bitfire.davdroid.resource.RemoteCollection; @@ -26,12 +30,24 @@ public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter { protected AccountManager accountManager; + private static String androidID; + + public DavSyncAdapter(Context context) { super(context, true); + + androidID = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); + accountManager = AccountManager.get(context); } + + public static String generateUID() { + UidGenerator generator = new UidGenerator(new SimpleHostInfo(androidID), String.valueOf(android.os.Process.myPid())); + return generator.generateUid().getValue(); + } + protected abstract Map, RemoteCollection> getSyncPairs(Account account, ContentProviderClient provider); diff --git a/src/at/bitfire/davdroid/syncadapter/EnterCredentialsFragment.java b/src/at/bitfire/davdroid/syncadapter/EnterCredentialsFragment.java index 188b1f1c..2eadbc04 100644 --- a/src/at/bitfire/davdroid/syncadapter/EnterCredentialsFragment.java +++ b/src/at/bitfire/davdroid/syncadapter/EnterCredentialsFragment.java @@ -7,6 +7,9 @@ ******************************************************************************/ package at.bitfire.davdroid.syncadapter; +import java.net.MalformedURLException; +import java.net.URL; + import android.app.DialogFragment; import android.app.Fragment; import android.app.FragmentTransaction; @@ -38,11 +41,6 @@ public class EnterCredentialsFragment extends Fragment implements TextWatcher { Button btnNext; - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.enter_credentials, container, false); @@ -103,10 +101,9 @@ public class EnterCredentialsFragment extends Fragment implements TextWatcher { void queryServer() { FragmentTransaction ft = getFragmentManager().beginTransaction(); - String host_path = editBaseURL.getText().toString(); - Bundle args = new Bundle(); + String host_path = editBaseURL.getText().toString(); args.putString(QueryServerDialogFragment.EXTRA_BASE_URL, URIUtils.sanitize(protocol + host_path)); args.putString(QueryServerDialogFragment.EXTRA_USER_NAME, editUserName.getText().toString()); args.putString(QueryServerDialogFragment.EXTRA_PASSWORD, editPassword.getText().toString()); @@ -118,15 +115,22 @@ public class EnterCredentialsFragment extends Fragment implements TextWatcher { } - // form validation + // input validation @Override public void onPrepareOptionsMenu(Menu menu) { boolean ok = - editBaseURL.getText().length() > 0 && - !editBaseURL.getText().toString().startsWith("/") && // host name required editUserName.getText().length() > 0 && editPassword.getText().length() > 0; + + // check host name + try { + URL url = new URL(protocol + editBaseURL.getText().toString()); + if (url.getHost() == null || url.getHost().isEmpty()) + ok = false; + } catch (MalformedURLException e) { + ok = false; + } MenuItem item = menu.findItem(R.id.next); item.setEnabled(ok); diff --git a/src/at/bitfire/davdroid/syncadapter/SelectCollectionsFragment.java b/src/at/bitfire/davdroid/syncadapter/SelectCollectionsFragment.java index 87584ba2..2a3de201 100644 --- a/src/at/bitfire/davdroid/syncadapter/SelectCollectionsFragment.java +++ b/src/at/bitfire/davdroid/syncadapter/SelectCollectionsFragment.java @@ -7,19 +7,8 @@ ******************************************************************************/ package at.bitfire.davdroid.syncadapter; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.LinkedList; -import java.util.List; - -import android.accounts.Account; -import android.accounts.AccountManager; import android.app.ListFragment; -import android.content.ContentResolver; import android.os.Bundle; -import android.os.RemoteException; -import android.provider.CalendarContract; -import android.provider.ContactsContract; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -30,10 +19,7 @@ import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ListAdapter; import android.widget.ListView; -import android.widget.Toast; -import at.bitfire.davdroid.Constants; import at.bitfire.davdroid.R; -import at.bitfire.davdroid.resource.LocalCalendar; public class SelectCollectionsFragment extends ListFragment { public static final String KEY_SERVER_INFO = "server_info"; @@ -45,6 +31,12 @@ public class SelectCollectionsFragment extends ListFragment { return v; } + @Override + public void onDestroyView() { + super.onDestroyView(); + setListAdapter(null); + } + @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); @@ -84,8 +76,32 @@ public class SelectCollectionsFragment extends ListFragment { @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.add_account: - addAccount(); + case R.id.next: + ServerInfo serverInfo = (ServerInfo)getArguments().getSerializable(KEY_SERVER_INFO); + + // synchronize only selected collections + for (ServerInfo.ResourceInfo addressBook : serverInfo.getAddressBooks()) + addressBook.setEnabled(false); + for (ServerInfo.ResourceInfo calendar : serverInfo.getCalendars()) + calendar.setEnabled(false); + + ListAdapter adapter = getListView().getAdapter(); + for (long id : getListView().getCheckedItemIds()) { + int position = (int)id + 1; // +1 because header view is inserted at pos. 0 + ServerInfo.ResourceInfo info = (ServerInfo.ResourceInfo)adapter.getItem(position); + 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() + .replace(R.id.fragment_container, accountDetails) + .addToBackStack(null) + .commitAllowingStateLoss(); break; default: return false; @@ -94,7 +110,7 @@ public class SelectCollectionsFragment extends ListFragment { } - // form validation + // input validation @Override public void onPrepareOptionsMenu(Menu menu) { @@ -103,65 +119,7 @@ public class SelectCollectionsFragment extends ListFragment { ok = getListView().getCheckedItemCount() > 0; } catch(IllegalStateException e) { } - MenuItem item = menu.findItem(R.id.add_account); + MenuItem item = menu.findItem(R.id.next); item.setEnabled(ok); } - - - // actions - - void addAccount() { - List addressBooks = new LinkedList(), - calendars = new LinkedList(); - - ListAdapter adapter = getListView().getAdapter(); - for (long id : getListView().getCheckedItemIds()) { - int position = (int)id + 1; // +1 because header view is inserted at pos. 0 - ServerInfo.ResourceInfo info = (ServerInfo.ResourceInfo)adapter.getItem(position); - switch (info.getType()) { - case ADDRESS_BOOK: - addressBooks.add(info); - break; - case CALENDAR: - calendars.add(info); - } - } - - ServerInfo serverInfo = (ServerInfo)getArguments().getSerializable(KEY_SERVER_INFO); - try { - URI baseURI = new URI(serverInfo.getBaseURL()); - String accountName = serverInfo.getUserName() + "@" + baseURI.getHost() + baseURI.getPath(); - - AccountManager accountManager = AccountManager.get(getActivity()); - Account account = new Account(accountName, Constants.ACCOUNT_TYPE); - Bundle userData = new Bundle(); - userData.putString(Constants.ACCOUNT_KEY_BASE_URL, serverInfo.getBaseURL()); - userData.putString(Constants.ACCOUNT_KEY_USERNAME, serverInfo.getUserName()); - userData.putString(Constants.ACCOUNT_KEY_AUTH_PREEMPTIVE, Boolean.toString(serverInfo.isAuthPreemptive())); - - if (!addressBooks.isEmpty()) { - userData.putString(Constants.ACCOUNT_KEY_ADDRESSBOOK_PATH, addressBooks.get(0).getPath()); - 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)) { - // account created, now create calendars - if (!calendars.isEmpty()) { - for (ServerInfo.ResourceInfo calendar : calendars) - LocalCalendar.create(account, getActivity().getContentResolver(), calendar); - ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, 1); - ContentResolver.setSyncAutomatically(account, CalendarContract.AUTHORITY, true); - } else - ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, 0); - - getActivity().finish(); - } else - Toast.makeText(getActivity(), "Couldn't create account (already existing?)", Toast.LENGTH_LONG).show(); - - } catch (URISyntaxException e) { - } catch (RemoteException e) { - } - } } diff --git a/src/at/bitfire/davdroid/syncadapter/ServerInfo.java b/src/at/bitfire/davdroid/syncadapter/ServerInfo.java index e530e341..50cac503 100644 --- a/src/at/bitfire/davdroid/syncadapter/ServerInfo.java +++ b/src/at/bitfire/davdroid/syncadapter/ServerInfo.java @@ -8,6 +8,7 @@ package at.bitfire.davdroid.syncadapter; import java.io.Serializable; +import java.util.LinkedList; import java.util.List; import lombok.Data; @@ -25,7 +26,17 @@ public class ServerInfo implements Serializable { private String errorMessage; private boolean calDAV, cardDAV; - private List addressBooks, calendars; + private List + addressBooks = new LinkedList(), + calendars = new LinkedList(); + + public boolean hasEnabledCalendars() { + for (ResourceInfo calendar : calendars) + if (calendar.enabled) + return true; + return false; + } + @RequiredArgsConstructor(suppressConstructorProperties=true) @Data @@ -37,6 +48,8 @@ public class ServerInfo implements Serializable { CALENDAR } + boolean enabled = false; + final Type type; final String path, title, description, color; diff --git a/test/src/at/bitfire/davdroid/test/CalendarTest.java b/test/src/at/bitfire/davdroid/test/CalendarTest.java index cf2828c9..b8b1d4b8 100644 --- a/test/src/at/bitfire/davdroid/test/CalendarTest.java +++ b/test/src/at/bitfire/davdroid/test/CalendarTest.java @@ -10,7 +10,6 @@ package at.bitfire.davdroid.test; import java.io.IOException; import java.io.InputStream; -import junit.framework.Assert; import net.fortuna.ical4j.data.ParserException; import android.content.res.AssetManager; import android.test.InstrumentationTestCase; @@ -26,10 +25,11 @@ public class CalendarTest extends InstrumentationTestCase { public void testTimeZonesByEvolution() throws IOException, ParserException { Event e = parseCalendar("vienna-evolution.ics"); - Assert.assertEquals("Test-Ereignis im schönen Wien", e.getSummary()); + assertEquals("Test-Ereignis im schönen Wien", e.getSummary()); //DTSTART;TZID=/freeassociation.sourceforge.net/Tzfile/Europe/Vienna:20131009T170000 - Assert.assertEquals(1381327200, e.getDtStartInMillis()); + /*assertEquals(1381330800000L, e.getDtStartInMillis()); + assertEquals(1381334400000L, (long)e.getDtEndInMillis());*/ }