Commit 6372af79 authored by Ricki Hirner's avatar Ricki Hirner

Refactoring

* use Kotlin getters/setters, if possible
* simplify interfaces
* reduce importance of CalendarStorageException (now used as a separate exception only,
  not as a wrapper for RemoteException)
parent 2576dc6e
......@@ -66,7 +66,7 @@ class AndroidCalendarTest {
assertNotNull(uri)
// query task list
val calendar = AndroidCalendar.findByID(testAccount, provider, TestCalendar.Factory.INSTANCE, ContentUris.parseId(uri))
val calendar = AndroidCalendar.findByID(testAccount, provider, TestCalendar.Factory, ContentUris.parseId(uri))
assertNotNull(calendar)
// delete task list
......
......@@ -118,7 +118,7 @@ class AndroidEventTest {
val uri = TestEvent(calendar, event).add()
assertNotNull(uri)
val testEvent = TestEvent(calendar, ContentUris.parseId(uri))
val testEvent = calendar.findById(ContentUris.parseId(uri))
try {
// read and parse event from calendar provider
......@@ -189,7 +189,7 @@ class AndroidEventTest {
val uri = TestEvent(calendar, event).add()
// update test event in calendar
val testEvent = TestEvent(calendar, ContentUris.parseId(uri))
val testEvent = calendar.findById(ContentUris.parseId(uri))
val event2 = testEvent.event!!
event2.summary = "Updated event"
// add data rows
......@@ -198,7 +198,7 @@ class AndroidEventTest {
val uri2 = testEvent.update(event2)
// read again and verify result
val updatedEvent = TestEvent(calendar, ContentUris.parseId(uri2))
val updatedEvent = calendar.findById(ContentUris.parseId(uri2))
try {
val event3 = updatedEvent.event!!
assertEquals(event2.summary, event3.summary)
......@@ -221,7 +221,7 @@ class AndroidEventTest {
event.attendees += Attendee(URI("mailto:att$i@example.com"))
val uri = TestEvent(calendar, event).add()
val testEvent = TestEvent(calendar, ContentUris.parseId(uri))
val testEvent = calendar.findById(ContentUris.parseId(uri))
try {
assertEquals(4000, testEvent.event!!.attendees.size)
} finally {
......@@ -259,7 +259,7 @@ class AndroidEventTest {
val uri = TestEvent(calendar, event).add()
assertNotNull(uri)
val testEvent = TestEvent(calendar, ContentUris.parseId(uri))
val testEvent = calendar.findById(ContentUris.parseId(uri))
try {
// read again and verify result
val event2 = testEvent.event!!
......@@ -285,7 +285,7 @@ class AndroidEventTest {
val uri = TestEvent(calendar, event).add()
assertNotNull(uri)
val testEvent = TestEvent(calendar, ContentUris.parseId(uri))
val testEvent = calendar.findById(ContentUris.parseId(uri))
try {
// read again and verify result
val event2 = testEvent.event!!
......@@ -309,7 +309,7 @@ class AndroidEventTest {
val uri = TestEvent(calendar, event).add()
assertNotNull(uri)
val testEvent = TestEvent(calendar, ContentUris.parseId(uri))
val testEvent = calendar.findById(ContentUris.parseId(uri))
try {
// read again and verify result
val event2 = testEvent.event!!
......@@ -340,7 +340,7 @@ class AndroidEventTest {
calendar.provider.update(calendar.syncAdapterURI(ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, id)),
values, null, null)
val testEvent = TestEvent(calendar, id)
val testEvent = calendar.findById(id)
try {
// read again and verify result
val event2 = testEvent.event!!
......@@ -355,7 +355,7 @@ class AndroidEventTest {
values, null, null)
// read again and verify result
val testEventPrivate = TestEvent(calendar, id)
val testEventPrivate = calendar.findById(id)
val eventPrivate = testEventPrivate.event!!
// should be PRIVATE
assertEquals(Clazz.PRIVATE, eventPrivate.classification)
......@@ -378,7 +378,7 @@ class AndroidEventTest {
assertNotNull(uri)
val id = ContentUris.parseId(uri)
val testEvent = TestEvent(calendar, id)
val testEvent = calendar.findById(id)
try {
// read again and verify result
val event2 = testEvent.event!!
......@@ -412,7 +412,7 @@ class AndroidEventTest {
val uri = TestEvent(calendar, event).add()
assertNotNull(uri)
val testEvent = TestEvent(calendar, ContentUris.parseId(uri))
val testEvent = calendar.findById(ContentUris.parseId(uri))
try {
// read again and verify result
val event2 = testEvent.event!!
......@@ -434,7 +434,7 @@ class AndroidEventTest {
values.put(CalendarContract.Events.TITLE, "Without dtend/duration")
val uri = provider.insert(syncAdapterURI(CalendarContract.Events.CONTENT_URI, testAccount), values)
val testEvent = TestEvent(calendar, ContentUris.parseId(uri))
val testEvent = calendar.findById(ContentUris.parseId(uri))
try {
assertNull(testEvent.event!!.dtEnd)
} finally {
......@@ -453,7 +453,7 @@ class AndroidEventTest {
val uri = TestEvent(calendar, event).add()
assertNotNull(uri)
val testEvent = TestEvent(calendar, ContentUris.parseId(uri))
val testEvent = calendar.findById(ContentUris.parseId(uri))
try {
// read again and verify result
val event2 = testEvent.event!!
......
......@@ -58,7 +58,7 @@ class AndroidTaskListTest {
assertNotNull(uri)
// query task list
val taskList = AndroidTaskList.findByID(testAccount, provider!!, TestTaskList.Factory.FACTORY, ContentUris.parseId(uri))
val taskList = AndroidTaskList.findByID(testAccount, provider!!, TestTaskList.Factory, ContentUris.parseId(uri))
assertNotNull(taskList)
// delete task list
......
......@@ -48,7 +48,7 @@ class AndroidTaskTest {
assumeNotNull(providerOrNull)
provider = providerOrNull!!
taskList = TestTaskList.findOrCreate(testAccount, provider)
taskList = TestTaskList.create(testAccount, providerOrNull)
assertNotNull("Couldn't find/create test task list", taskList)
taskListUri = ContentUris.withAppendedId(provider!!.taskListsUri(), taskList!!.id)
......@@ -78,11 +78,11 @@ class AndroidTaskTest {
assertFalse(task.isAllDay())
// add to task list
val uri = TestTask(taskList, task).add()
val uri = TestTask(taskList!!, task).add()
assertNotNull("Couldn't add task", uri)
// read and parse event from calendar provider
val testTask = TestTask(taskList, ContentUris.parseId(uri))
val testTask = taskList!!.findById(ContentUris.parseId(uri))
try {
assertNotNull("Inserted task is not here", testTask)
val task2 = testTask.task
......@@ -107,7 +107,7 @@ class AndroidTaskTest {
task.dtStart = DtStart(Date("20150102"))
task.due = Due(Date("20150101"))
TestTask(taskList, task).add()
TestTask(taskList!!, task).add()
}
@MediumTest
......@@ -121,10 +121,10 @@ class AndroidTaskTest {
task.location = "Sample location"
task.dtStart = DtStart("20150501T120000", tzVienna)
assertFalse(task.isAllDay())
val uri = TestTask(taskList, task).add()
val uri = TestTask(taskList!!, task).add()
assertNotNull(uri)
val testTask = TestTask(taskList, ContentUris.parseId(uri))
val testTask = taskList!!.findById(ContentUris.parseId(uri))
try {
// update test event in calendar
val task2 = testTask.task!!
......@@ -134,7 +134,7 @@ class AndroidTaskTest {
testTask.update(task)
// read again and verify result
val updatedTask = TestTask(taskList, ContentUris.parseId(uri)).task!!
val updatedTask = taskList!!.findById(ContentUris.parseId(uri)).task!!
assertEquals(task.summary, updatedTask.summary)
assertEquals(task.dtStart, updatedTask.dtStart)
assertEquals(task.due, updatedTask.due)
......@@ -154,10 +154,10 @@ class AndroidTaskTest {
task.dtStart = DtStart(Date("20150501"))
task.due = Due(Date("20150502"))
assertTrue(task.isAllDay())
val uri = TestTask(taskList, task).add()
val uri = TestTask(taskList!!, task).add()
assertNotNull(uri)
val testTask = TestTask(taskList, ContentUris.parseId(uri))
val testTask = taskList!!.findById(ContentUris.parseId(uri))
try {
// read again and verify result
val task2 = testTask.task!!
......@@ -176,16 +176,16 @@ class AndroidTaskTest {
@Test
fun testGetTimeZone() {
// no date/time
var t = TestTask(taskList, Task())
var t = TestTask(taskList!!, Task())
assertEquals(TimeZone.getDefault(), t.getTimeZone())
// dtstart with date (no time)
t = TestTask(taskList, Task())
t = TestTask(taskList!!, Task())
t.task!!.dtStart = DtStart("20150101")
assertEquals(TimeZone.getDefault(), t.getTimeZone())
// dtstart with time
t = TestTask(taskList, Task())
t = TestTask(taskList!!, Task())
t.task!!.dtStart = (DtStart("20150101", tzVienna))
assertEquals(tzVienna, t.getTimeZone())
}
......
/*
* Copyright © 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.ical4android.impl;
import android.accounts.Account;
import android.content.ContentProviderClient;
import android.content.ContentUris;
import android.content.ContentValues;
import android.net.Uri;
import android.provider.CalendarContract;
import android.util.Log;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import at.bitfire.ical4android.AndroidCalendar;
import at.bitfire.ical4android.AndroidCalendarFactory;
import at.bitfire.ical4android.CalendarStorageException;
public class TestCalendar extends AndroidCalendar<TestEvent> {
private static final String TAG = "ical4android.TestCal";
public TestCalendar(Account account, ContentProviderClient provider, long id) {
super(account, provider, TestEvent.Factory.INSTANCE, id);
}
static public TestCalendar findOrCreate(Account account, ContentProviderClient provider) throws CalendarStorageException {
List<TestCalendar> calendars = AndroidCalendar.find(account, provider, Factory.INSTANCE, null, null);
if (calendars.size() == 0) {
Log.i(TAG, "Test calendar not found, creating");
ContentValues values = new ContentValues();
values.put(CalendarContract.Calendars.NAME, "TestCalendar");
values.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, "ical4android Test Calendar");
values.put(CalendarContract.Calendars.ALLOWED_REMINDERS,
CalendarContract.Reminders.METHOD_DEFAULT);
Uri uri = AndroidCalendar.create(account, provider, values);
return new TestCalendar(account, provider, ContentUris.parseId(uri));
} else
return calendars.get(0);
}
public static class Factory implements AndroidCalendarFactory<TestCalendar> {
public static final Factory INSTANCE = new Factory();
@NotNull
@Override
public TestCalendar newInstance(@NotNull Account account, @NotNull ContentProviderClient provider, long id) {
return new TestCalendar(account, provider, id);
}
}
}
/*
* Copyright © 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.ical4android.impl
import android.accounts.Account
import android.content.ContentProviderClient
import android.content.ContentUris
import android.content.ContentValues
import android.provider.CalendarContract
import at.bitfire.ical4android.AndroidCalendar
import at.bitfire.ical4android.AndroidCalendarFactory
class TestCalendar(
account: Account,
providerClient: ContentProviderClient,
id: Long
): AndroidCalendar<TestEvent>(account, providerClient, TestEvent.Factory, id) {
companion object {
fun findOrCreate(account: Account, provider: ContentProviderClient): TestCalendar {
val calendars = AndroidCalendar.find(account, provider, Factory, null, null)
if (calendars.isEmpty()) {
val values = ContentValues(3)
values.put(CalendarContract.Calendars.NAME, "TestCalendar")
values.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, "ical4android Test Calendar")
values.put(CalendarContract.Calendars.ALLOWED_REMINDERS,
CalendarContract.Reminders.METHOD_DEFAULT)
val uri = AndroidCalendar.create(account, provider, values)
return TestCalendar(account, provider, ContentUris.parseId(uri))
} else
return calendars.first()
}
}
object Factory: AndroidCalendarFactory<TestCalendar> {
override fun newInstance(account: Account, provider: ContentProviderClient, id: Long) =
TestCalendar(account, provider, id)
}
}
/*
* Copyright © 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.ical4android.impl;
import android.content.ContentValues;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import at.bitfire.ical4android.AndroidCalendar;
import at.bitfire.ical4android.AndroidEvent;
import at.bitfire.ical4android.AndroidEventFactory;
import at.bitfire.ical4android.Event;
public class TestEvent extends AndroidEvent {
public TestEvent(AndroidCalendar calendar, long id) {
super(calendar, id, null);
}
public TestEvent(AndroidCalendar calendar, Event event) {
super(calendar, event);
}
public static class Factory implements AndroidEventFactory<TestEvent> {
public static final Factory INSTANCE = new Factory();
@NotNull
@Override
public TestEvent newInstance(@NotNull AndroidCalendar calendar, long id, @Nullable ContentValues baseInfo) {
return new TestEvent(calendar, id);
}
@NotNull
@Override
public TestEvent newInstance(@NotNull AndroidCalendar calendar, @NotNull Event event) {
return new TestEvent(calendar, event);
}
}
}
/*
* Copyright © 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.ical4android.impl
import android.content.ContentValues
import at.bitfire.ical4android.AndroidCalendar
import at.bitfire.ical4android.AndroidEvent
import at.bitfire.ical4android.AndroidEventFactory
import at.bitfire.ical4android.Event
class TestEvent: AndroidEvent {
constructor(calendar: AndroidCalendar<AndroidEvent>, values: ContentValues)
: super(calendar, values)
constructor(calendar: TestCalendar, event: Event)
: super(calendar, event)
object Factory: AndroidEventFactory<TestEvent> {
override fun fromProvider(calendar: AndroidCalendar<AndroidEvent>, values: ContentValues) =
TestEvent(calendar, values)
}
}
......@@ -6,7 +6,7 @@
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.ical4android.impl;
package at.bitfire.ical4android.impl
import android.content.ContentValues;
......@@ -15,31 +15,17 @@ import at.bitfire.ical4android.AndroidTaskFactory;
import at.bitfire.ical4android.AndroidTaskList;
import at.bitfire.ical4android.Task;
public class TestTask extends AndroidTask {
class TestTask: AndroidTask {
public TestTask(AndroidTaskList calendar, long id) {
super(calendar, id);
}
public TestTask(AndroidTaskList calendar, Task task) {
super(calendar, task);
}
public static class Factory implements AndroidTaskFactory<TestTask> {
public static final Factory FACTORY = new Factory();
@Override
public TestTask newInstance(AndroidTaskList taskList, long id, ContentValues baseInfo) {
return new TestTask(taskList, id);
}
constructor(taskList: AndroidTaskList<AndroidTask>, values: ContentValues)
: super(taskList, values)
@Override
public TestTask newInstance(AndroidTaskList taskList, Task task) {
return new TestTask(taskList, task);
}
constructor(taskList: TestTaskList, task: Task)
: super(taskList, task)
object Factory: AndroidTaskFactory<TestTask> {
override fun fromProvider(taskList: AndroidTaskList<AndroidTask>, values: ContentValues) =
TestTask(taskList, values)
}
}
/*
* Copyright © 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.ical4android.impl;
import android.accounts.Account;
import android.content.ContentUris;
import android.content.ContentValues;
import android.net.Uri;
import android.util.Log;
import org.dmfs.tasks.contract.TaskContract;
import at.bitfire.ical4android.AndroidTaskList;
import at.bitfire.ical4android.AndroidTaskListFactory;
import at.bitfire.ical4android.CalendarStorageException;
import at.bitfire.ical4android.TaskProvider;
public class TestTaskList extends AndroidTaskList<TestTask> {
private static final String TAG = "ical4android.TestCal";
protected TestTaskList(Account account, TaskProvider provider, long id) {
super(account, provider, TestTask.Factory.FACTORY, id);
}
public static TestTaskList findOrCreate(Account account, TaskProvider provider) throws CalendarStorageException {
TestTaskList[] taskLists = new TestTaskList[0]; /*findAll()*/
if (taskLists.length == 0) {
Log.i(TAG, "Test calendar not found, creating");
ContentValues values = new ContentValues();
values.put(TaskContract.TaskListColumns.LIST_NAME, "Test Task List");
values.put(TaskContract.TaskListColumns.LIST_COLOR, 0xffff0000);
values.put(TaskContract.TaskListColumns.SYNC_ENABLED, 1);
values.put(TaskContract.TaskListColumns.VISIBLE, 1);
Uri uri = AndroidTaskList.create(account, provider, values);
return new TestTaskList(account, provider, ContentUris.parseId(uri));
} else
return taskLists[0];
}
public static class Factory implements AndroidTaskListFactory<TestTaskList> {
public static final Factory FACTORY = new Factory();
@Override
public TestTaskList newInstance(Account account, TaskProvider provider, long id) {
return new TestTaskList(account, provider, id);
}
}
}
/*
* Copyright © 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.ical4android.impl
import android.accounts.Account
import android.content.ContentUris
import android.content.ContentValues
import at.bitfire.ical4android.AndroidTaskList
import at.bitfire.ical4android.AndroidTaskListFactory
import at.bitfire.ical4android.TaskProvider
import org.dmfs.tasks.contract.TaskContract
class TestTaskList(
account: Account,
provider: TaskProvider,
id: Long
): AndroidTaskList<TestTask>(account, provider, TestTask.Factory, id) {
companion object {
fun create(account: Account, provider: TaskProvider): TestTaskList {
val values = ContentValues(4)
values.put(TaskContract.TaskListColumns.LIST_NAME, "Test Task List")
values.put(TaskContract.TaskListColumns.LIST_COLOR, 0xffff0000)
values.put(TaskContract.TaskListColumns.SYNC_ENABLED, 1)
values.put(TaskContract.TaskListColumns.VISIBLE, 1)
val uri = AndroidTaskList.create(account, provider, values)
return TestTaskList(account, provider, ContentUris.parseId(uri))
}
}
object Factory: AndroidTaskListFactory<TestTaskList> {
override fun newInstance(account: Account, provider: TaskProvider, id: Long) =
TestTaskList(account, provider, id)
}
}
......@@ -9,20 +9,18 @@
package at.bitfire.ical4android
import android.accounts.Account
import android.annotation.SuppressLint
import android.content.ContentProviderClient
import android.content.ContentUris
import android.content.ContentValues
import android.database.DatabaseUtils
import android.net.Uri
import android.os.RemoteException
import android.provider.CalendarContract
import android.provider.CalendarContract.*
import java.io.FileNotFoundException
import java.util.*
/**
* Represents a locally stored calendar, containing AndroidEvents (whose data objects are Events).
* Represents a locally stored calendar, containing [AndroidEvent]s (whose data objects are [Event]s).
* Communicates with the Android Contacts Provider which uses an SQLite
* database to store the events.
*/
......@@ -33,23 +31,8 @@ abstract class AndroidCalendar<out T: AndroidEvent>(
val id: Long
) {
var name: String? = null
var displayName: String? = null
var color: Int? = null
var isSynced = true
var isVisible = true
/**
* Those CalendarContract.Events columns will always be fetched by queryEvents().
* Must at least contain Events._ID!
*/
protected open fun eventBaseInfoColumns() = arrayOf(Events._ID)
companion object {
@JvmStatic
@Throws(CalendarStorageException::class)
fun create(account: Account, provider: ContentProviderClient, info: ContentValues): Uri {
info.put(Calendars.ACCOUNT_NAME, account.name)
info.put(Calendars.ACCOUNT_TYPE, account.type)
......@@ -59,14 +42,9 @@ abstract class AndroidCalendar<out T: AndroidEvent>(
info.put(Calendars.ALLOWED_ATTENDEE_TYPES, "${Attendees.TYPE_NONE},${Attendees.TYPE_OPTIONAL},${Attendees.TYPE_REQUIRED},${Attendees.TYPE_RESOURCE}")
Constants.log.info("Creating local calendar: " + info.toString())
try {
return provider.insert(syncAdapterURI(Calendars.CONTENT_URI, account), info)
} catch(e: RemoteException) {
throw CalendarStorageException("Couldn't create calendar", e)
}
return provider.insert(syncAdapterURI(Calendars.CONTENT_URI, account), info)
}
@JvmStatic
fun insertColors(provider: ContentProviderClient, account: Account) {
provider.query(syncAdapterURI(Colors.CONTENT_URI, account), arrayOf(Colors.COLOR_KEY), null, null, null)?.use { cursor ->
if (cursor.count == EventColor.values().size)
......@@ -86,7 +64,6 @@ abstract class AndroidCalendar<out T: AndroidEvent>(
}
}
@JvmStatic
fun removeColors(provider: ContentProviderClient, account: Account) {
Constants.log.info("Removing event colors from account $account")
......@@ -103,9 +80,6 @@ abstract class AndroidCalendar<out T: AndroidEvent>(
provider.delete(syncAdapterURI(Colors.CONTENT_URI, account), null, null)
}
@SuppressLint("Recycle")
@JvmStatic
@Throws(FileNotFoundException::class, CalendarStorageException::class)
fun<T: AndroidCalendar<AndroidEvent>> findByID(account: Account, provider: ContentProviderClient, factory: AndroidCalendarFactory<T>, id: Long): T {
val iterCalendars = CalendarContract.CalendarEntity.newEntityIterator(
provider.query(syncAdapterURI(ContentUris.withAppendedId(CalendarContract.CalendarEntity.CONTENT_URI, id), account), null, null, null, null)
......@@ -117,17 +91,12 @@ abstract class AndroidCalendar<out T: AndroidEvent>(
calendar.populate(values)
return calendar
}
} catch(e: RemoteException) {
throw CalendarStorageException("Couldn't query calendars", e)
} finally {
iterCalendars.close()
}
throw FileNotFoundException()
}
@SuppressLint("Recycle")
@JvmStatic
@Throws(CalendarStorageException::class)
fun<T: AndroidCalendar<AndroidEvent>> find(account: Account, provider: ContentProviderClient, factory: AndroidCalendarFactory<T>, where: String?, whereArgs: Array<String>?): List<T> {
val iterCalendars = CalendarContract.CalendarEntity.newEntityIterator(
provider.query(syncAdapterURI(CalendarContract.CalendarEntity.CONTENT_URI, account), null, where, whereArgs, null)
......@@ -141,14 +110,11 @@ abstract class AndroidCalendar<out T: AndroidEvent>(
calendars += calendar
}
return calendars
} catch(e: RemoteException) {
throw CalendarStorageException("Couldn't query calendars", e)
} finally {
iterCalendars.close()
}
}
fun syncAdapterURI(uri: Uri, account: Account) = uri.buildUpon()
</