Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 83dab17f authored by Ricki Hirner's avatar Ricki Hirner
Browse files

Events: use ACCESS_CONFIDENTIAL

* export ACCESS_CONFIDENTIAL as CLASS:CONFIDENTIAL
* import CLASS:CONFIDENTIAL as ACCESS_CONFIDENTIAL and retain it as unknown property
* export ACCESS_DEFAULT as (no CLASS) when no CLASS is retained
* export ACCESS_DEFAULT as the retained CLASS value in case there is one
parent d04d1cc2
Loading
Loading
Loading
Loading
+60 −2
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import net.fortuna.ical4j.model.TimeZone;
import net.fortuna.ical4j.model.component.VAlarm;
import net.fortuna.ical4j.model.parameter.Value;
import net.fortuna.ical4j.model.property.Attendee;
import net.fortuna.ical4j.model.property.Clazz;
import net.fortuna.ical4j.model.property.DtEnd;
import net.fortuna.ical4j.model.property.DtStart;
import net.fortuna.ical4j.model.property.Duration;
@@ -108,7 +109,7 @@ public class AndroidEventTest extends InstrumentationTestCase {
        event.setDtEnd(new DtEnd("20150501T130000", tzVienna));
        event.setOrganizer(new Organizer(new URI("mailto:organizer@example.com")));
        event.setRRule(new RRule("FREQ=DAILY;COUNT=10"));
        event.setForPublic(false);
        event.setClassification(Clazz.PRIVATE);
        event.setStatus(Status.VEVENT_CONFIRMED);
        event.setColor(EventColor.aliceblue);
        assertFalse(event.isAllDay());
@@ -153,7 +154,7 @@ public class AndroidEventTest extends InstrumentationTestCase {
        assertFalse(event2.isAllDay());
        assertEquals(event.getOrganizer(), event2.getOrganizer());
        assertEquals(event.getRRule(), event2.getRRule());
        assertEquals(event.getForPublic(), event2.getForPublic());
        assertEquals(event.getClassification(), event2.getClassification());
        assertEquals(event.getStatus(), event2.getStatus());

        if (Build.VERSION.SDK_INT >= 23)
@@ -313,6 +314,63 @@ public class AndroidEventTest extends InstrumentationTestCase {
        assertTrue(event2.isAllDay());
    }

    public void testClassificationConfidential() throws Exception {
        Event event = new Event();
        event.setSummary("Confidential event");
        event.setDtStart(new DtStart(new Date("20150501")));
        event.setDtEnd(new DtEnd(new Date("20150502")));
        event.setClassification(Clazz.CONFIDENTIAL);
        Uri uri = new TestEvent(calendar, event).add();
        assertNotNull("Couldn't add event", uri);
        long id = ContentUris.parseId(uri);

        // now, the calendar app changes to ACCESS_DEFAULT
        ContentValues values = new ContentValues(1);
        values.put(CalendarContract.Events.ACCESS_LEVEL, CalendarContract.Events.ACCESS_DEFAULT);
        calendar.getProvider().update(calendar.syncAdapterURI(ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, id)),
                values, null, null);

        // read again and verify result
        @Cleanup("delete") TestEvent testEvent = new TestEvent(calendar, id);
        Event event2 = testEvent.getEvent();
        // CONFIDENTIAL has been retained
        assertTrue(event.getUnknownProperties().contains(Clazz.CONFIDENTIAL));
        // should still be CONFIDENTIAL
        assertEquals(event.getClassification(), event2.getClassification());

        // now, the calendar app changes to ACCESS_PRIVATE
        values.put(CalendarContract.Events.ACCESS_LEVEL, CalendarContract.Events.ACCESS_PRIVATE);
        calendar.getProvider().update(calendar.syncAdapterURI(ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, id)),
                values, null, null);

        // read again and verify result
        TestEvent testEventPrivate = new TestEvent(calendar, id);
        Event eventPrivate = testEventPrivate.getEvent();
        // should be PRIVATE
        assertEquals(Clazz.PRIVATE, eventPrivate.getClassification());
        // the retained value is not used in this case
        assertFalse(eventPrivate.getUnknownProperties().contains(Clazz.CONFIDENTIAL));
    }

    public void testClassificationPrivate() throws Exception {
        Event event = new Event();
        event.setSummary("Private event");
        event.setDtStart(new DtStart(new Date("20150501")));
        event.setDtEnd(new DtEnd(new Date("20150502")));
        event.setClassification(Clazz.PRIVATE);
        Uri uri = new TestEvent(calendar, event).add();
        assertNotNull("Couldn't add event", uri);
        long id = ContentUris.parseId(uri);

        // read again and verify result
        @Cleanup("delete") TestEvent testEvent = new TestEvent(calendar, id);
        Event event2 = testEvent.getEvent();
        // PRIVATE has not been retained
        assertFalse(event.getUnknownProperties().contains(Clazz.PRIVATE));
        // should still be PRIVATE
        assertEquals(Clazz.PRIVATE, event2.getClassification());
    }

    public void testNoOrganizerWithoutAttendees() throws ParseException, URISyntaxException, CalendarStorageException, FileNotFoundException {
        Event event = new Event();
        event.setSummary("Not a group-scheduled event");
+43 −11
Original line number Diff line number Diff line
@@ -101,6 +101,8 @@ abstract class AndroidEvent(
                    }
                populateExceptions()

                useRetainedClassification()

                /* remove ORGANIZER from all components if there are no attendees
                   (i.e. this is not a group-scheduled calendar entity) */
                if (event.attendees.isEmpty()) {
@@ -194,11 +196,10 @@ abstract class AndroidEvent(
        }

        // status
        event.status = when (row.getAsInteger(Events.STATUS)) {
            Events.STATUS_CONFIRMED -> Status.VEVENT_CONFIRMED
            Events.STATUS_TENTATIVE -> Status.VEVENT_TENTATIVE
            Events.STATUS_CANCELED  -> Status.VEVENT_CANCELLED
            else                    -> null
        when (row.getAsInteger(Events.STATUS)) {
            Events.STATUS_CONFIRMED -> event.status = Status.VEVENT_CONFIRMED
            Events.STATUS_TENTATIVE -> event.status = Status.VEVENT_TENTATIVE
            Events.STATUS_CANCELED  -> event.status = Status.VEVENT_CANCELLED
        }

        // availability
@@ -213,10 +214,10 @@ abstract class AndroidEvent(
            }

        // classification
        event.forPublic = when (row.getAsInteger(Events.ACCESS_LEVEL)) {
            Events.ACCESS_PUBLIC  -> true
            Events.ACCESS_PRIVATE -> false
            else                  -> null
        when (row.getAsInteger(Events.ACCESS_LEVEL)) {
            Events.ACCESS_PUBLIC       -> event.classification = Clazz.PUBLIC
            Events.ACCESS_PRIVATE      -> event.classification = Clazz.PRIVATE
            Events.ACCESS_CONFIDENTIAL -> event.classification = Clazz.CONFIDENTIAL
        }

        // exceptions from recurring events
@@ -350,6 +351,16 @@ abstract class AndroidEvent(
        }
    }

    private fun retainClassification() {
        /* retain classification other than PUBLIC and PRIVATE as unknown property so
           that it can be reused when "server default" is selected */
        val event = requireNotNull(event)
        event.classification?.let {
            if (it != Clazz.PUBLIC && it != Clazz.PRIVATE)
                event.unknownProperties += it
        }
    }


    @Throws(CalendarStorageException::class)
    fun add(): Uri {
@@ -377,6 +388,7 @@ abstract class AndroidEvent(
        event.attendees.forEach { insertAttendee(batch, idxEvent, it) }

        // add unknown properties
        retainClassification()
        event.unknownProperties.forEach { insertUnknownProperty(batch, idxEvent, it) }

        // add exceptions
@@ -567,8 +579,10 @@ abstract class AndroidEvent(

        builder.withValue(Events.AVAILABILITY, if (event.opaque) Events.AVAILABILITY_BUSY else Events.AVAILABILITY_FREE)

        event.forPublic?.let { forPublic ->
            builder.withValue(Events.ACCESS_LEVEL, if (forPublic) Events.ACCESS_PUBLIC else Events.ACCESS_PRIVATE)
        when (event.classification) {
            Clazz.PUBLIC       -> builder.withValue(Events.ACCESS_LEVEL, Events.ACCESS_PUBLIC)
            Clazz.PRIVATE      -> builder.withValue(Events.ACCESS_LEVEL, Events.ACCESS_PRIVATE)
            Clazz.CONFIDENTIAL -> builder.withValue(Events.ACCESS_LEVEL, Events.ACCESS_CONFIDENTIAL)
        }

        Constants.log.log(Level.FINE, "Built event object", builder.build())
@@ -673,6 +687,24 @@ abstract class AndroidEvent(
        }
    }

    private fun useRetainedClassification() {
        val event = requireNotNull(event)

        var retainedClazz: Clazz? = null
        val it = event.unknownProperties.iterator()
        while (it.hasNext()) {
            val prop = it.next()
            if (prop is Clazz) {
                retainedClazz = prop
                it.remove()
            }
        }

        if (event.classification == null)
            // no classification, use retained one if possible
            event.classification = retainedClazz
    }


    protected fun eventsSyncURI() = calendar.syncAdapterURI(Events.CONTENT_URI)

+4 −4
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ class Event: iCalendar() {

    val exceptions = LinkedList<Event>()

    var forPublic: Boolean? = null
    var classification: Clazz? = null
    var status: Status? = null

    var opaque = true
@@ -172,7 +172,7 @@ class Event: iCalendar() {
                    is RDate -> e.rDates += prop
                    is ExRule -> e.exRule = prop
                    is ExDate -> e.exDates += prop
                    is Clazz -> e.forPublic = prop == Clazz.PUBLIC
                    is Clazz -> e.classification = prop
                    is Status -> e.status = prop
                    is Transp -> e.opaque = prop == Transp.OPAQUE
                    is Organizer -> e.organizer = prop
@@ -252,6 +252,7 @@ class Event: iCalendar() {
        exRule?.let { props += it }
        props.addAll(exDates)

        classification?.let { props += it }
        status?.let { props += it }
        if (!opaque)
            props += Transp.TRANSPARENT
@@ -259,10 +260,9 @@ class Event: iCalendar() {
        organizer?.let { props += it }
        props.addAll(attendees)

        forPublic?.let { props += if (it) Clazz.PUBLIC else Clazz.PRIVATE }
        props.addAll(unknownProperties)

        lastModified?.let { props += it }
        props.addAll(unknownProperties)

        event.alarms.addAll(alarms)
        return event