diff --git a/app/src/androidTest/java/at/bitfire/davdroid/resource/LocalCalendarTest.java b/app/src/androidTest/java/at/bitfire/davdroid/resource/LocalCalendarTest.java index cb832dd7..e44afb6c 100644 --- a/app/src/androidTest/java/at/bitfire/davdroid/resource/LocalCalendarTest.java +++ b/app/src/androidTest/java/at/bitfire/davdroid/resource/LocalCalendarTest.java @@ -11,6 +11,7 @@ import android.Manifest; import android.accounts.Account; import android.annotation.TargetApi; import android.content.ContentProviderClient; +import android.content.ContentProviderOperation; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; @@ -26,11 +27,16 @@ import android.provider.CalendarContract.Reminders; import android.test.InstrumentationTestCase; import android.util.Log; +import net.fortuna.ical4j.model.Date; import net.fortuna.ical4j.model.DateList; +import net.fortuna.ical4j.model.Dur; import net.fortuna.ical4j.model.TimeZone; import net.fortuna.ical4j.model.TimeZoneRegistry; import net.fortuna.ical4j.model.TimeZoneRegistryFactory; +import net.fortuna.ical4j.model.component.VAlarm; import net.fortuna.ical4j.model.parameter.Value; +import net.fortuna.ical4j.model.property.DtEnd; +import net.fortuna.ical4j.model.property.DtStart; import net.fortuna.ical4j.model.property.RDate; import java.text.ParseException; @@ -39,103 +45,168 @@ import java.util.Calendar; import java.util.List; import java.util.SimpleTimeZone; +import at.bitfire.davdroid.Constants; +import at.bitfire.davdroid.webdav.DavProp; import lombok.Cleanup; public class LocalCalendarTest extends InstrumentationTestCase { - - private static final String - TAG = "davdroid.test", - accountName = "at.bitfire.davdroid.test", - calendarName = "DAVdroid_Test"; - Context targetContext; + private static final String + TAG = "davdroid.test", + accountType = "at.bitfire.davdroid.test", + calendarName = "DAVdroid_Test"; - ContentProviderClient providerClient; - Account testAccount = new Account(calendarName, CalendarContract.ACCOUNT_TYPE_LOCAL); - LocalCalendar testCalendar; + Context targetContext; + + ContentProviderClient providerClient; + Account testAccount = new Account(calendarName, accountType); + + Uri calendarURI; + LocalCalendar testCalendar; - // helpers - - private Uri syncAdapterURI(Uri uri) { - return uri.buildUpon() - .appendQueryParameter(Calendars.ACCOUNT_TYPE, CalendarContract.ACCOUNT_TYPE_LOCAL) - .appendQueryParameter(Calendars.ACCOUNT_NAME, accountName) - .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true"). - build(); - } - - private long insertNewEvent() throws LocalStorageException, RemoteException { - ContentValues values = new ContentValues(); - values.put(Events.CALENDAR_ID, testCalendar.getId()); - values.put(Events.TITLE, "Test Event"); - values.put(Events.ALL_DAY, 0); - values.put(Events.DTSTART, Calendar.getInstance().getTimeInMillis()); - values.put(Events.DTEND, Calendar.getInstance().getTimeInMillis()); - values.put(Events.EVENT_TIMEZONE, "UTC"); - values.put(Events.DIRTY, 1); - return ContentUris.parseId(providerClient.insert(syncAdapterURI(Events.CONTENT_URI), values)); - } - - private void deleteEvent(long id) throws RemoteException { - providerClient.delete(syncAdapterURI(ContentUris.withAppendedId(Events.CONTENT_URI, id)), null, null); - } - - - // initialization - - @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) - protected void setUp() throws Exception { - targetContext = getInstrumentation().getTargetContext(); - targetContext.enforceCallingOrSelfPermission(Manifest.permission.READ_CALENDAR, "No privileges for enumerating calendars"); + // helpers - providerClient = targetContext.getContentResolver().acquireContentProviderClient(CalendarContract.AUTHORITY); - - long calendarId; + private Uri syncAdapterURI(Uri uri) { + return uri.buildUpon() + .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType) + .appendQueryParameter(Calendars.ACCOUNT_NAME, accountType) + .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true"). + build(); + } - @Cleanup Cursor cursor = providerClient.query(Calendars.CONTENT_URI, - new String[]{ Calendars._ID }, - Calendars.ACCOUNT_TYPE + "=? AND " + Calendars.ACCOUNT_NAME + "=? AND " + Calendars.NAME + "=?", - new String[] { CalendarContract.ACCOUNT_TYPE_LOCAL, accountName, calendarName }, - null); - if (cursor != null && cursor.moveToNext()) { - calendarId = cursor.getLong(0); - Log.i(TAG, "Found test calendar with ID " + calendarId); - - } else { - // no local test calendar found, create - ContentValues values = new ContentValues(); - values.put(Calendars.ACCOUNT_NAME, testAccount.name); - values.put(Calendars.ACCOUNT_TYPE, testAccount.type); - values.put(Calendars.NAME, calendarName); - values.put(Calendars.CALENDAR_DISPLAY_NAME, calendarName); - values.put(Calendars.CALENDAR_ACCESS_LEVEL, Calendars.CAL_ACCESS_OWNER); - values.put(Calendars.ALLOWED_REMINDERS, Reminders.METHOD_ALERT); - values.put(Calendars.SYNC_EVENTS, 0); - values.put(Calendars.VISIBLE, 1); - - if (android.os.Build.VERSION.SDK_INT >= 15) { - 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_OPTIONAL + "," + Attendees.TYPE_REQUIRED + "," + Attendees.TYPE_RESOURCE); - } - - Uri calendarURI = providerClient.insert(syncAdapterURI(Calendars.CONTENT_URI), values); - - calendarId = ContentUris.parseId(calendarURI); - Log.d(TAG, "Created test calendar with ID " + calendarId); + private long insertNewEvent() throws LocalStorageException, RemoteException { + ContentValues values = new ContentValues(); + values.put(Events.CALENDAR_ID, testCalendar.getId()); + values.put(Events.TITLE, "Test Event"); + values.put(Events.ALL_DAY, 0); + values.put(Events.DTSTART, Calendar.getInstance().getTimeInMillis()); + values.put(Events.DTEND, Calendar.getInstance().getTimeInMillis()); + values.put(Events.EVENT_TIMEZONE, "UTC"); + values.put(Events.DIRTY, 1); + return ContentUris.parseId(providerClient.insert(syncAdapterURI(Events.CONTENT_URI), values)); + } + + private void deleteEvent(long id) throws RemoteException { + providerClient.delete(syncAdapterURI(ContentUris.withAppendedId(Events.CONTENT_URI, id)), null, null); + } + + + // initialization + + @Override + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) + protected void setUp() throws LocalStorageException, RemoteException { + targetContext = getInstrumentation().getTargetContext(); + targetContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_CALENDAR, "No privileges for managing calendars"); + + providerClient = targetContext.getContentResolver().acquireContentProviderClient(CalendarContract.AUTHORITY); + + prepareTestCalendar(); + } + + private void prepareTestCalendar() throws LocalStorageException, RemoteException { + @Cleanup Cursor cursor = providerClient.query(Calendars.CONTENT_URI, new String[] { Calendars._ID }, + Calendars.ACCOUNT_TYPE + "=? AND " + Calendars.ACCOUNT_NAME + "=?", + new String[] { testAccount.type, testAccount.name }, null); + if (cursor != null && cursor.moveToNext()) + calendarURI = ContentUris.withAppendedId(Calendars.CONTENT_URI, cursor.getLong(0)); + else { + ServerInfo.ResourceInfo info = new ServerInfo.ResourceInfo(ServerInfo.ResourceInfo.Type.CALENDAR, false, null, "Test Calendar", null, null); + calendarURI = LocalCalendar.create(testAccount, targetContext.getContentResolver(), info); + } + + Log.i(TAG, "Prepared test calendar " + calendarURI); + testCalendar = new LocalCalendar(testAccount, providerClient, ContentUris.parseId(calendarURI), null); + } + + @Override + protected void tearDown() throws RemoteException { + deleteTestCalendar(); + } + + protected void deleteTestCalendar() throws RemoteException { + Uri uri = ContentUris.withAppendedId(Calendars.CONTENT_URI, testCalendar.id); + if (providerClient.delete(uri,null,null)>0) + Log.i(TAG,"Deleted test calendar "+uri); + else + Log.e(TAG,"Couldn't delete test calendar "+uri); + } + + + // tests + + public void testBuildEntry() throws LocalStorageException, ParseException { + final String vcardName = "testBuildEntry"; + + TimeZoneRegistry tzRegistry = TimeZoneRegistryFactory.getInstance().createRegistry(); + TimeZone tzVienna = tzRegistry.getTimeZone("Europe/Vienna"); + assertNotNull(tzVienna); + + // build and write event to calendar provider + Event event = new Event(vcardName, null); + event.summary = "Sample event"; + event.description = "Sample event with date/time"; + event.location = "Sample location"; + event.dtStart = new DtStart("20150501T120000", tzVienna); + event.dtEnd = new DtEnd("20150501T130000", tzVienna); + assertFalse(event.isAllDay()); + + // set an alarm one day, two hours, three minutes and four seconds before begin of event + event.getAlarms().add(new VAlarm(new Dur(-1, -2, -3, -4))); + + testCalendar.add(event); + testCalendar.commit(); + + // read and parse event from calendar provider + Event event2 = testCalendar.findByRemoteName(vcardName, true); + assertNotNull("Couldn't build and insert event", event); + // compare with original event + try { + assertEquals(event.getSummary(), event2.getSummary()); + assertEquals(event.getDescription(), event2.getDescription()); + assertEquals(event.getLocation(), event2.getLocation()); + assertEquals(event.getDtStart(), event2.getDtStart()); + assertFalse(event2.isAllDay()); + + assertEquals(1, event2.getAlarms().size()); + VAlarm alarm = event2.getAlarms().get(0); + assertEquals(event.getSummary(), alarm.getDescription().getValue()); // should be built from event name + assertEquals(new Dur(0, 0, -(24*60 + 60*2 + 3), 0), alarm.getTrigger().getDuration()); // calendar provider stores trigger in minutes + } finally { + testCalendar.delete(event); } - - testCalendar = new LocalCalendar(testAccount, providerClient, calendarId, null); } - protected void tearDown() throws Exception { - Uri uri = ContentUris.withAppendedId(syncAdapterURI(Calendars.CONTENT_URI), testCalendar.getId()); - providerClient.delete(uri, null, null); + public void testBuildAllDayEntry() throws LocalStorageException, ParseException { + final String vcardName = "testBuildAllDayEntry"; + + // build and write event to calendar provider + Event event = new Event(vcardName, null); + event.summary = "All-day event"; + event.description = "All-day event for testing"; + event.location = "Sample location testBuildAllDayEntry"; + event.dtStart = new DtStart(new Date("20150501")); + event.dtEnd = new DtEnd(new Date("20150502")); + assertTrue(event.isAllDay()); + testCalendar.add(event); + testCalendar.commit(); + + // read and parse event from calendar provider + Event event2 = testCalendar.findByRemoteName(vcardName, true); + assertNotNull("Couldn't build and insert event", event); + // compare with original event + try { + assertEquals(event.getSummary(), event2.getSummary()); + assertEquals(event.getDescription(), event2.getDescription()); + assertEquals(event.getLocation(), event2.getLocation()); + assertEquals(event.getDtStart(), event2.getDtStart()); + assertTrue(event2.isAllDay()); + } finally { + testCalendar.delete(event); + } } - - // tests - public void testCTags() throws LocalStorageException { assertNull(testCalendar.getCTag()); diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5af8ee25..c5fa1ca9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,7 +9,7 @@ + android:label="@string/settings_title" + android:parentActivityName=".ui.settings.SettingsActivity" > diff --git a/app/src/main/java/at/bitfire/davdroid/Constants.java b/app/src/main/java/at/bitfire/davdroid/Constants.java index a52a5991..f600e200 100644 --- a/app/src/main/java/at/bitfire/davdroid/Constants.java +++ b/app/src/main/java/at/bitfire/davdroid/Constants.java @@ -9,7 +9,7 @@ package at.bitfire.davdroid; public class Constants { public static final String - APP_VERSION = "0.7.6", + APP_VERSION = "0.7.7", ACCOUNT_TYPE = "bitfire.at.davdroid", 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"; diff --git a/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.java b/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.java index eaf70ca7..a661d6fc 100644 --- a/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.java +++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.java @@ -121,7 +121,7 @@ public class LocalCalendar extends LocalCollection { /* class methods, constructor */ @SuppressLint("InlinedApi") - public static void 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(CalendarContract.AUTHORITY); if (client == null) throw new LocalStorageException("No Calendar Provider found (Calendar app disabled?)"); @@ -166,8 +166,8 @@ public class LocalCalendar extends LocalCollection { Log.i(TAG, "Inserting calendar: " + values.toString() + " -> " + calendarsURI(account).toString()); try { - client.insert(calendarsURI(account), values); - } catch(RemoteException e) { + return client.insert(calendarsURI(account), values); + } catch (RemoteException e) { throw new LocalStorageException(e); } } diff --git a/app/src/main/java/at/bitfire/davdroid/ui/settings/AccountActivity.java b/app/src/main/java/at/bitfire/davdroid/ui/settings/AccountActivity.java index 561c0c7c..3273d73e 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/settings/AccountActivity.java +++ b/app/src/main/java/at/bitfire/davdroid/ui/settings/AccountActivity.java @@ -24,6 +24,7 @@ public class AccountActivity extends Activity { super.onCreate(savedInstanceState); setContentView(R.layout.settings_account_activity); + getActionBar().setDisplayHomeAsUpEnabled(true); final FragmentManager fm = getFragmentManager();