Add 'alarms' table

pull/618/head
Alex Baker 7 years ago
parent 8a1cbe1c8c
commit 46acf31e22

@ -0,0 +1,629 @@
{
"formatVersion": 1,
"database": {
"version": 47,
"identityHash": "d34ba028da3599fe5ea241c5c619aa6c",
"entities": [
{
"tableName": "notification",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `type` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "uid",
"columnName": "uid",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "taskId",
"columnName": "task",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"uid"
],
"autoGenerate": true
},
"indices": [
{
"name": "index_notification_task",
"unique": true,
"columnNames": [
"task"
],
"createSql": "CREATE UNIQUE INDEX `index_notification_task` ON `${TABLE_NAME}` (`task`)"
}
],
"foreignKeys": []
},
{
"tableName": "tagdata",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `name` TEXT, `color` INTEGER, `tagOrdering` TEXT, `deleted` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remoteId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "color",
"columnName": "color",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "tagOrdering",
"columnName": "tagOrdering",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "userActivity",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `action` TEXT, `message` TEXT, `picture` TEXT, `target_id` TEXT, `created_at` INTEGER, `deleted_at` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remoteId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "action",
"columnName": "action",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "message",
"columnName": "message",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "picture",
"columnName": "picture",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "targetId",
"columnName": "target_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "created",
"columnName": "created_at",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted_at",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "task_attachments",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `task_id` TEXT, `name` TEXT, `path` TEXT, `content_type` TEXT, `deleted_at` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remoteId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "taskId",
"columnName": "task_id",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "path",
"columnName": "path",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "contentType",
"columnName": "content_type",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted_at",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "task_list_metadata",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `remoteId` TEXT, `tag_uuid` TEXT, `filter` TEXT, `task_ids` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remoteId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "tagUuid",
"columnName": "tag_uuid",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "filter",
"columnName": "filter",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "taskIds",
"columnName": "task_ids",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "store",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `type` TEXT, `item` TEXT, `value` TEXT, `value2` TEXT, `value3` TEXT, `value4` TEXT, `deleted` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "item",
"columnName": "item",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "value",
"columnName": "value",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "value2",
"columnName": "value2",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "value3",
"columnName": "value3",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "value4",
"columnName": "value4",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [
{
"name": "so_id",
"unique": false,
"columnNames": [
"type",
"item"
],
"createSql": "CREATE INDEX `so_id` ON `${TABLE_NAME}` (`type`, `item`)"
}
],
"foreignKeys": []
},
{
"tableName": "tasks",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `title` TEXT, `importance` INTEGER, `dueDate` INTEGER, `hideUntil` INTEGER, `created` INTEGER, `modified` INTEGER, `completed` INTEGER, `deleted` INTEGER, `notes` TEXT, `estimatedSeconds` INTEGER, `elapsedSeconds` INTEGER, `timerStart` INTEGER, `notificationFlags` INTEGER, `notifications` INTEGER, `lastNotified` INTEGER, `snoozeTime` INTEGER, `recurrence` TEXT, `repeatUntil` INTEGER, `calendarUri` TEXT, `remoteId` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "importance",
"columnName": "importance",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "dueDate",
"columnName": "dueDate",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "hideUntil",
"columnName": "hideUntil",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "created",
"columnName": "created",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "modified",
"columnName": "modified",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "completed",
"columnName": "completed",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "notes",
"columnName": "notes",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "estimatedSeconds",
"columnName": "estimatedSeconds",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "elapsedSeconds",
"columnName": "elapsedSeconds",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "timerStart",
"columnName": "timerStart",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "notificationFlags",
"columnName": "notificationFlags",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "notifications",
"columnName": "notifications",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "lastNotified",
"columnName": "lastNotified",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "snoozeTime",
"columnName": "snoozeTime",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "recurrence",
"columnName": "recurrence",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "repeatUntil",
"columnName": "repeatUntil",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "calendarUri",
"columnName": "calendarUri",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "remoteId",
"columnName": "remoteId",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [
{
"name": "t_rid",
"unique": true,
"columnNames": [
"remoteId"
],
"createSql": "CREATE UNIQUE INDEX `t_rid` ON `${TABLE_NAME}` (`remoteId`)"
}
],
"foreignKeys": []
},
{
"tableName": "metadata",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `task` INTEGER, `key` TEXT, `value` TEXT, `value2` TEXT, `value3` TEXT, `value4` TEXT, `value5` TEXT, `value6` TEXT, `value7` TEXT, `created` INTEGER, `deleted` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "task",
"columnName": "task",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "key",
"columnName": "key",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "value1",
"columnName": "value",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "value2",
"columnName": "value2",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "value3",
"columnName": "value3",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "value4",
"columnName": "value4",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "value5",
"columnName": "value5",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "value6",
"columnName": "value6",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "value7",
"columnName": "value7",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "created",
"columnName": "created",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [
{
"name": "md_tid",
"unique": false,
"columnNames": [
"task"
],
"createSql": "CREATE INDEX `md_tid` ON `${TABLE_NAME}` (`task`)"
},
{
"name": "md_tkid",
"unique": false,
"columnNames": [
"task",
"key"
],
"createSql": "CREATE INDEX `md_tkid` ON `${TABLE_NAME}` (`task`, `key`)"
}
],
"foreignKeys": []
},
{
"tableName": "alarms",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `task` INTEGER, `time` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "task",
"columnName": "task",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"d34ba028da3599fe5ea241c5c619aa6c\")"
]
}
}

@ -1,35 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.alarms;
import com.todoroo.andlib.data.Property.IntegerProperty;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.astrid.data.Metadata;
/**
* Metadata entry for a task alarm
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class AlarmFields {
/** metadata key */
public static final String METADATA_KEY = "alarm"; //$NON-NLS-1$
/** time of alarm */
public static final LongProperty TIME = new LongProperty(Metadata.TABLE,
Metadata.VALUE1.name);
/** alarm type */
public static final IntegerProperty TYPE = new IntegerProperty(Metadata.TABLE,
Metadata.VALUE2.name);
// --- constants
/** this alarm is single-shot */
public static final int TYPE_SINGLE = 1;
}

@ -5,29 +5,15 @@
*/
package com.todoroo.astrid.alarms;
import android.content.ContentValues;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.SynchronizeMetadataCallback;
import org.tasks.data.Alarm;
import org.tasks.data.AlarmDao;
import org.tasks.injection.ApplicationScope;
import org.tasks.jobs.AlarmJob;
import org.tasks.jobs.JobQueue;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
@ -44,12 +30,11 @@ public class AlarmService {
private static final long NO_ALARM = Long.MAX_VALUE;
private final JobQueue jobs;
private final MetadataDao metadataDao;
private final AlarmDao alarmDao;
@Inject
public AlarmService(MetadataDao metadataDao, JobQueue jobQueue) {
this.metadataDao = metadataDao;
public AlarmService(AlarmDao alarmDao, JobQueue jobQueue) {
this.alarmDao = alarmDao;
jobs = jobQueue;
}
@ -59,18 +44,16 @@ public class AlarmService {
}
final Set<Long> alarms = new LinkedHashSet<>();
for (Metadata metadata : getAlarms(taskId)) {
alarms.add(metadata.getValue(AlarmFields.TIME) + (newDueDate - oldDueDate));
for (Alarm alarm : getAlarms(taskId)) {
alarms.add(alarm.getTime() + (newDueDate - oldDueDate));
}
if (!alarms.isEmpty()) {
synchronizeAlarms(taskId, alarms);
}
}
public List<Metadata> getAlarms(long taskId) {
return metadataDao.toList(Query.select(
Metadata.PROPERTIES).where(MetadataCriteria.byTaskAndwithKey(
taskId, AlarmFields.METADATA_KEY)).orderBy(Order.asc(AlarmFields.TIME)));
public List<org.tasks.data.Alarm> getAlarms(long taskId) {
return alarmDao.getAlarms(taskId);
}
/**
@ -78,12 +61,10 @@ public class AlarmService {
* @return true if data was changed
*/
public boolean synchronizeAlarms(final long taskId, Set<Long> alarms) {
List<Metadata> metadata = new ArrayList<>();
List<Alarm> metadata = new ArrayList<>();
for(Long alarm : alarms) {
Metadata item = new Metadata();
item.setKey(AlarmFields.METADATA_KEY);
item.setValue(AlarmFields.TIME, alarm);
item.setValue(AlarmFields.TYPE, AlarmFields.TYPE_SINGLE);
Alarm item = new Alarm();
item.setTime(alarm);
metadata.add(item);
}
@ -97,28 +78,20 @@ public class AlarmService {
// --- alarm scheduling
private List<Metadata> getActiveAlarms() {
return metadataDao.toList(Query.select(Metadata.PROPERTIES).
join(Join.inner(Task.TABLE, Metadata.TASK.eq(Task.ID))).
where(Criterion.and(TaskCriteria.isActive(),
Task.REMINDER_LAST.lt(AlarmFields.TIME),
MetadataCriteria.withKey(AlarmFields.METADATA_KEY))));
private List<org.tasks.data.Alarm> getActiveAlarms() {
return alarmDao.getActiveAlarms();
}
private List<Metadata> getActiveAlarmsForTask(long taskId) {
return metadataDao.toList(Query.select(Metadata.PROPERTIES).
join(Join.inner(Task.TABLE, Metadata.TASK.eq(Task.ID))).
where(Criterion.and(TaskCriteria.isActive(),
Task.REMINDER_LAST.lt(AlarmFields.TIME),
MetadataCriteria.byTaskAndwithKey(taskId, AlarmFields.METADATA_KEY))));
private List<org.tasks.data.Alarm> getActiveAlarmsForTask(long taskId) {
return alarmDao.getActiveAlarms(taskId);
}
/**
* Schedules all alarms
*/
public void scheduleAllAlarms() {
for (Metadata metadata : getActiveAlarms()) {
scheduleAlarm(metadata);
for (Alarm alarm : getActiveAlarms()) {
scheduleAlarm(alarm);
}
}
@ -126,20 +99,20 @@ public class AlarmService {
* Schedules alarms for a single task
*/
private void scheduleAlarms(long taskId) {
for (Metadata metadata : getActiveAlarmsForTask(taskId)) {
scheduleAlarm(metadata);
for (Alarm alarm : getActiveAlarmsForTask(taskId)) {
scheduleAlarm(alarm);
}
}
/**
* Schedules alarms for a single task
*/
private void scheduleAlarm(Metadata metadata) {
if(metadata == null) {
private void scheduleAlarm(Alarm alarm) {
if(alarm == null) {
return;
}
AlarmJob alarmJob = new AlarmJob(metadata);
AlarmJob alarmJob = new AlarmJob(alarm);
long time = alarmJob.getTime();
if(time == 0 || time == NO_ALARM) {
jobs.cancelAlarm(alarmJob.getId());
@ -148,54 +121,41 @@ public class AlarmService {
}
}
private boolean synchronizeMetadata(long taskId, List<Metadata> metadata, final SynchronizeMetadataCallback callback) {
final boolean[] dirty = new boolean[1];
final Set<ContentValues> newMetadataValues = new HashSet<>();
for(Metadata metadatum : metadata) {
public interface SynchronizeAlarmCallback {
void beforeDelete(Alarm alarm);
}
private boolean synchronizeMetadata(long taskId, List<Alarm> alarms, final SynchronizeAlarmCallback callback) {
boolean dirty = false;
for(Alarm metadatum : alarms) {
metadatum.setTask(taskId);
metadatum.clearValue(Metadata.CREATION_DATE);
metadatum.clearValue(Metadata.ID);
ContentValues values = metadatum.getMergedValues();
for(Map.Entry<String, Object> entry : values.valueSet()) {
if(entry.getKey().startsWith("value")) //$NON-NLS-1$
{
values.put(entry.getKey(), entry.getValue().toString());
}
}
newMetadataValues.add(values);
metadatum.setId(0L);
}
for (Metadata item : metadataDao.byTaskAndKey(taskId, AlarmFields.METADATA_KEY)) {
for (Alarm item : alarmDao.getAlarms(taskId)) {
long id = item.getId();
// clear item id when matching with incoming values
item.clearValue(Metadata.ID);
item.clearValue(Metadata.CREATION_DATE);
ContentValues itemMergedValues = item.getMergedValues();
if(newMetadataValues.contains(itemMergedValues)) {
newMetadataValues.remove(itemMergedValues);
item.setId(0L);
if(alarms.contains(item)) {
alarms.remove(item);
} else {
// not matched. cut it
item.setId(id);
if (callback != null) {
callback.beforeDeleteMetadata(item);
callback.beforeDelete(item);
}
metadataDao.delete(id);
dirty[0] = true;
alarmDao.delete(item);
dirty = true;
}
}
// everything that remains shall be written
for(ContentValues values : newMetadataValues) {
Metadata item = new Metadata();
item.setCreationDate(DateUtilities.now());
item.mergeWith(values);
metadataDao.persist(item);
dirty[0] = true;
for(Alarm alarm : alarms) {
alarmDao.insert(alarm);
dirty = true;
}
return dirty[0];
return dirty;
}
}

@ -37,6 +37,8 @@ class BackupConstants {
/** Tag containing a metadata item */
public static final String METADATA_TAG = "metadata";
public static final String ALARM_TAG = "alarm";
/** Tag containing a tagdata item */
public static final String TAGDATA_TAG = "tagdata";

@ -31,6 +31,8 @@ import com.todoroo.astrid.data.UserActivity;
import org.tasks.R;
import org.tasks.backup.XmlWriter;
import org.tasks.data.Alarm;
import org.tasks.data.AlarmDao;
import org.tasks.preferences.Preferences;
import org.xmlpull.v1.XmlSerializer;
@ -61,6 +63,7 @@ public class TasksXmlExporter {
private final TagDataDao tagDataDao;
private final MetadataDao metadataDao;
private final AlarmDao alarmDao;
private final TaskDao taskDao;
private UserActivityDao userActivityDao;
private final Preferences preferences;
@ -91,12 +94,13 @@ public class TasksXmlExporter {
@Inject
public TasksXmlExporter(TagDataDao tagDataDao, MetadataDao metadataDao, TaskDao taskDao, UserActivityDao userActivityDao,
Preferences preferences) {
Preferences preferences, AlarmDao alarmDao) {
this.tagDataDao = tagDataDao;
this.metadataDao = metadataDao;
this.taskDao = taskDao;
this.userActivityDao = userActivityDao;
this.preferences = preferences;
this.alarmDao = alarmDao;
}
public void exportTasks(final Context context, final ExportType exportType, @Nullable final ProgressDialog progressDialog) {
@ -184,6 +188,7 @@ public class TasksXmlExporter {
xml.startTag(null, BackupConstants.TASK_TAG);
serializeModel(task, Task.PROPERTIES, Task.ID);
serializeMetadata(task);
serializeAlarms(task);
serializeComments(task);
xml.endTag(null, BackupConstants.TASK_TAG);
this.exportCount++;
@ -218,6 +223,18 @@ public class TasksXmlExporter {
}
}
private synchronized void serializeAlarms(Task task) {
for (Alarm alarm : alarmDao.getAlarms(task.getId())) {
try {
xml.startTag(null, BackupConstants.ALARM_TAG);
alarm.writeToXml(new XmlWriter(xml));
xml.endTag(null, BackupConstants.ALARM_TAG);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/**
* Turn a model into xml attributes
*/

@ -32,6 +32,8 @@ import com.todoroo.astrid.tags.TaskToTagMetadata;
import org.tasks.LocalBroadcastManager;
import org.tasks.R;
import org.tasks.backup.XmlReader;
import org.tasks.data.Alarm;
import org.tasks.data.AlarmDao;
import org.tasks.dialogs.DialogBuilder;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@ -53,6 +55,7 @@ public class TasksXmlImporter {
private final DialogBuilder dialogBuilder;
private final TaskDao taskDao;
private LocalBroadcastManager localBroadcastManager;
private final AlarmDao alarmDao;
private Activity activity;
private Handler handler;
@ -69,13 +72,15 @@ public class TasksXmlImporter {
@Inject
public TasksXmlImporter(TagDataDao tagDataDao, MetadataDao metadataDao, UserActivityDao userActivityDao,
DialogBuilder dialogBuilder, TaskDao taskDao, LocalBroadcastManager localBroadcastManager) {
DialogBuilder dialogBuilder, TaskDao taskDao,
LocalBroadcastManager localBroadcastManager, AlarmDao alarmDao) {
this.tagDataDao = tagDataDao;
this.metadataDao = metadataDao;
this.userActivityDao = userActivityDao;
this.dialogBuilder = dialogBuilder;
this.taskDao = taskDao;
this.localBroadcastManager = localBroadcastManager;
this.alarmDao = alarmDao;
}
public void importTasks(Activity activity, String input, ProgressDialog progressDialog) {
@ -230,12 +235,29 @@ public class TasksXmlImporter {
userActivityDao.createNew(userActivity);
}
void parseAlarm() {
if (!currentTask.isSaved()) {
return;
}
Alarm alarm = new Alarm(new XmlReader(xpp));
alarmDao.insert(alarm);
}
void parseMetadata(int format) {
if(!currentTask.isSaved()) {
return;
}
metadata.clear();
deserializeModel(metadata, Metadata.PROPERTIES);
if (metadata.getKey().equals("alarm")) {
Alarm alarm = new Alarm();
alarm.setTask(currentTask.getId());
alarm.setTime(Long.valueOf(metadata.getValue(Metadata.VALUE1)));
alarmDao.insert(new Alarm());
return;
}
if (metadata.getKey().equals(TaskToTagMetadata.KEY)) {
String uuid = metadata.getValue(TaskToTagMetadata.TAG_UUID);
List<Metadata> metadatas = metadataDao.byTaskAndKey(currentTask.getId(), TaskToTagMetadata.KEY);
@ -356,6 +378,9 @@ public class TasksXmlImporter {
case BackupConstants.TAGDATA_TAG:
parseTagdata();
break;
case BackupConstants.ALARM_TAG:
parseAlarm();
break;
}
} catch (Exception e) {
errorCount++;

@ -23,6 +23,8 @@ import com.todoroo.astrid.data.TaskAttachment;
import com.todoroo.astrid.data.TaskListMetadata;
import com.todoroo.astrid.data.UserActivity;
import org.tasks.data.Alarm;
import org.tasks.data.AlarmDao;
import org.tasks.notifications.Notification;
import org.tasks.notifications.NotificationDao;
@ -45,9 +47,10 @@ import timber.log.Timber;
TaskListMetadata.class,
StoreObject.class,
Task.class,
Metadata.class
Metadata.class,
Alarm.class
},
version = 46)
version = 47)
public abstract class Database extends RoomDatabase {
public abstract NotificationDao notificationDao();
@ -56,6 +59,7 @@ public abstract class Database extends RoomDatabase {
public abstract TaskAttachmentDao getTaskAttachmentDao();
public abstract TaskListMetadataDao getTaskListMetadataDao();
public abstract StoreObjectDao getStoreObjectDao();
public abstract AlarmDao getAlarmDao();
public static final String NAME = "database";

@ -6,7 +6,6 @@
package com.todoroo.astrid.dao;
import com.todoroo.andlib.data.DatabaseDao;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Query;

@ -23,7 +23,6 @@ import android.widget.TextView;
import com.google.common.primitives.Longs;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.alarms.AlarmFields;
import com.todoroo.astrid.alarms.AlarmService;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
@ -31,6 +30,7 @@ import com.todoroo.astrid.data.Task;
import org.tasks.R;
import org.tasks.activities.DateAndTimePickerActivity;
import org.tasks.activities.TimePickerActivity;
import org.tasks.data.Alarm;
import org.tasks.injection.ForActivity;
import org.tasks.injection.FragmentComponent;
import org.tasks.location.Geofence;
@ -141,8 +141,8 @@ public class ReminderControlSet extends TaskEditControlFragment {
private List<Long> currentAlarms() {
final List<Long> alarms = new ArrayList<>();
for (Metadata entry : alarmService.getAlarms(taskId)) {
alarms.add(entry.getValue(AlarmFields.TIME));
for (Alarm entry : alarmService.getAlarms(taskId)) {
alarms.add(entry.getTime());
}
return alarms;
}

@ -0,0 +1,91 @@
package org.tasks.data;
import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.Ignore;
import android.arch.persistence.room.PrimaryKey;
import org.tasks.backup.XmlReader;
import org.tasks.backup.XmlWriter;
@Entity(tableName = "alarms")
public class Alarm {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "_id")
private Long id;
@ColumnInfo(name = "task")
private Long task;
@ColumnInfo(name = "time")
private Long time;
public Alarm() {
}
@Ignore
public Alarm(XmlReader xml) {
xml.readLong("task", this::setTask);
xml.readLong("time", this::setTime);
}
public void writeToXml(XmlWriter writer) {
writer.writeLong("task", task);
writer.writeLong("time", time);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getTask() {
return task;
}
public void setTask(Long task) {
this.task = task;
}
public Long getTime() {
return time;
}
public void setTime(Long time) {
this.time = time;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Alarm alarm = (Alarm) o;
if (id != null ? !id.equals(alarm.id) : alarm.id != null) return false;
if (task != null ? !task.equals(alarm.task) : alarm.task != null) return false;
return time != null ? time.equals(alarm.time) : alarm.time == null;
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (task != null ? task.hashCode() : 0);
result = 31 * result + (time != null ? time.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Alarm{" +
"id=" + id +
", task=" + task +
", time=" + time +
'}';
}
}

@ -0,0 +1,30 @@
package org.tasks.data;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Delete;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.Query;
import java.util.List;
@Dao
public interface AlarmDao {
@Query("SELECT alarms.* FROM alarms INNER JOIN tasks ON tasks._id = alarms._id " +
"WHERE tasks.completed = 0 AND tasks.deleted = 0 AND tasks.lastNotified < alarms.time " +
"ORDER BY time ASC")
List<Alarm> getActiveAlarms();
@Query("SELECT alarms.* FROM alarms INNER JOIN tasks ON tasks._id = alarms._id " +
"WHERE tasks._id = :taskId AND tasks.completed = 0 AND tasks.deleted = 0 AND tasks.lastNotified < alarms.time " +
"ORDER BY time ASC")
List<Alarm> getActiveAlarms(long taskId);
@Query("SELECT * FROM alarms WHERE task = :taskId ORDER BY time ASC")
List<Alarm> getAlarms(long taskId);
@Delete
void delete(Alarm alarm);
@Insert
void insert(Alarm alarm);
}

@ -34,6 +34,15 @@ public class Migrations {
}
};
private static final Migration MIGRATION_46_47 = new Migration(46, 47) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE IF NOT EXISTS `alarms` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `task` INTEGER, `time` INTEGER)");
database.execSQL("INSERT INTO `alarms` (`task`, `time`) SELECT `task`, `value` FROM `metadata` WHERE `key` = 'alarm'");
database.execSQL("DELETE FROM `metadata` WHERE `key` = 'alarm'");
}
};
private static Migration NOOP(int from, int to) {
return new Migration(from, to) {
@Override
@ -54,6 +63,7 @@ public class Migrations {
NOOP(42, 43),
NOOP(43, 44),
NOOP(44, 45),
NOOP(45, 46)
NOOP(45, 46),
MIGRATION_46_47
};
}

@ -13,6 +13,7 @@ import com.todoroo.astrid.provider.Astrid2TaskProvider;
import org.tasks.ErrorReportingSingleThreadExecutor;
import org.tasks.analytics.Tracker;
import org.tasks.data.AlarmDao;
import org.tasks.db.Migrations;
import org.tasks.locale.Locale;
import org.tasks.notifications.NotificationDao;
@ -90,4 +91,9 @@ public class ApplicationModule {
public StoreObjectDao getStoreObjectDao(Database database) {
return database.getStoreObjectDao();
}
@Provides
public AlarmDao getAlarmDao(Database database) {
return database.getAlarmDao();
}
}

@ -1,9 +1,8 @@
package org.tasks.jobs;
import com.todoroo.astrid.alarms.AlarmFields;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.reminders.ReminderService;
import org.tasks.data.Alarm;
import org.tasks.notifications.Notification;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
@ -13,8 +12,8 @@ public class AlarmJob implements JobQueueEntry {
private final long taskId;
private final long time;
public AlarmJob(Metadata metadata) {
this(metadata.getId(), metadata.getTask(), metadata.getValue(AlarmFields.TIME));
public AlarmJob(Alarm alarm) {
this(alarm.getId(), alarm.getTask(), alarm.getTime());
}
public AlarmJob(long alarmId, long taskId, Long time) {

Loading…
Cancel
Save