Add 'locations' table

pull/618/head
Alex Baker 6 years ago
parent ddf6b75f7d
commit 6a284db1a3

@ -0,0 +1,679 @@
{
"formatVersion": 1,
"database": {
"version": 48,
"identityHash": "a102567219ce1411936177294f59a581",
"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 NOT NULL, `task` INTEGER NOT NULL, `time` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "task",
"columnName": "task",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"_id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "locations",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `name` TEXT, `latitude` REAL NOT NULL, `longitude` REAL NOT NULL, `radius` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "task",
"columnName": "task",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "latitude",
"columnName": "latitude",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "longitude",
"columnName": "longitude",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "radius",
"columnName": "radius",
"affinity": "INTEGER",
"notNull": true
}
],
"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, \"a102567219ce1411936177294f59a581\")"
]
}
}

@ -9,8 +9,10 @@ import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationServices;
import com.google.common.collect.Lists;
import org.tasks.R;
import org.tasks.data.Location;
import org.tasks.injection.ForApplication;
import org.tasks.preferences.PermissionChecker;
import org.tasks.preferences.Preferences;
@ -40,8 +42,8 @@ public class GeofenceApi {
this.permissionChecker = permissionChecker;
}
public void register(final List<Geofence> geofences) {
if (geofences.isEmpty() || !permissionChecker.canAccessLocation()) {
public void register(final List<Location> locations) {
if (locations.isEmpty() || !permissionChecker.canAccessLocation()) {
return;
}
@ -50,13 +52,13 @@ public class GeofenceApi {
@SuppressLint("MissingPermission")
PendingResult<Status> result = LocationServices.GeofencingApi.addGeofences(
client,
getRequests(geofences),
getRequests(locations),
PendingIntent.getBroadcast(context, 0, new Intent(context, GeofenceTransitionsIntentService.Broadcast.class), PendingIntent.FLAG_UPDATE_CURRENT));
result.setResultCallback(status -> {
if (status.isSuccess()) {
Timber.i("Registered %s", geofences);
Timber.i("Registered %s", locations);
} else {
Timber.e("Failed to register %s", geofences);
Timber.e("Failed to register %s", locations);
}
client.disconnect();
@ -64,23 +66,23 @@ public class GeofenceApi {
});
}
public void cancel(final Geofence geofence) {
cancel(singletonList(geofence));
public void cancel(final Location location) {
cancel(singletonList(location));
}
public void cancel(final List<Geofence> geofences) {
if (geofences.isEmpty() || !permissionChecker.canAccessLocation()) {
public void cancel(final List<Location> locations) {
if (locations.isEmpty() || !permissionChecker.canAccessLocation()) {
return;
}
final List<String> ids = newArrayList(transform(geofences, geofence -> Long.toString(geofence.getMetadataId())));
List<String> ids = Lists.transform(locations, geofence -> Long.toString(geofence.getId()));
newClient(client -> LocationServices.GeofencingApi.removeGeofences(client, ids)
.setResultCallback(status -> {
if (status.isSuccess()) {
Timber.i("Removed %s", geofences);
Timber.i("Removed %s", locations);
} else {
Timber.e("Failed to remove %s", geofences);
Timber.e("Failed to remove %s", locations);
}
client.disconnect();
@ -91,17 +93,17 @@ public class GeofenceApi {
new GoogleApi(context).connect(handler);
}
private List<com.google.android.gms.location.Geofence> getRequests(List<Geofence> geofences) {
return newArrayList(transform(geofences, this::toGoogleGeofence));
private List<com.google.android.gms.location.Geofence> getRequests(List<Location> locations) {
return newArrayList(transform(locations, this::toGoogleGeofence));
}
private com.google.android.gms.location.Geofence toGoogleGeofence(Geofence geofence) {
private com.google.android.gms.location.Geofence toGoogleGeofence(Location location) {
int radius = preferences.getIntegerFromString(R.string.p_geofence_radius, 250);
int responsiveness = (int) TimeUnit.SECONDS.toMillis(preferences.getIntegerFromString(R.string.p_geofence_responsiveness, 60));
return new com.google.android.gms.location.Geofence.Builder()
.setCircularRegion(geofence.getLatitude(), geofence.getLongitude(), radius)
.setCircularRegion(location.getLatitude(), location.getLongitude(), radius)
.setNotificationResponsiveness(responsiveness)
.setRequestId(Long.toString(geofence.getMetadataId()))
.setRequestId(Long.toString(location.getId()))
.setTransitionTypes(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.setExpirationDuration(NEVER_EXPIRE)
.build();

@ -6,11 +6,11 @@ import android.content.Intent;
import android.support.v4.app.JobIntentService;
import com.google.android.gms.location.GeofencingEvent;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.reminders.ReminderService;
import org.tasks.Notifier;
import org.tasks.data.Location;
import org.tasks.data.LocationDao;
import org.tasks.injection.InjectingJobIntentService;
import org.tasks.injection.IntentServiceComponent;
import org.tasks.jobs.JobManager;
@ -30,7 +30,7 @@ public class GeofenceTransitionsIntentService extends InjectingJobIntentService
}
}
@Inject MetadataDao metadataDao;
@Inject LocationDao locationDao;
@Inject Notifier notifier;
@Override
@ -64,9 +64,8 @@ public class GeofenceTransitionsIntentService extends InjectingJobIntentService
private void triggerNotification(com.google.android.gms.location.Geofence triggeringGeofence) {
String requestId = triggeringGeofence.getRequestId();
try {
Metadata fetch = metadataDao.fetch(Long.parseLong(requestId));
Geofence geofence = new Geofence(fetch);
notifier.triggerTaskNotification(geofence.getTaskId(), ReminderService.TYPE_ALARM);
Location location = locationDao.getGeofence(Long.parseLong(requestId));
notifier.triggerTaskNotification(location.getTask(), ReminderService.TYPE_ALARM);
} catch(Exception e) {
Timber.e(e, "Error triggering geofence %s: %s", requestId, e.getMessage());
}

@ -11,6 +11,7 @@ import com.google.android.gms.location.places.Place;
import com.google.android.gms.maps.model.LatLng;
import org.tasks.R;
import org.tasks.data.Location;
import org.tasks.preferences.Preferences;
import timber.log.Timber;
@ -31,11 +32,15 @@ public class PlacePicker {
return null;
}
public static Geofence getPlace(Context context, Intent data, Preferences preferences) {
public static Location getPlace(Context context, Intent data, Preferences preferences) {
Place place = com.google.android.gms.location.places.ui.PlacePicker.getPlace(context, data);
LatLng latLng = place.getLatLng();
Geofence geofence = new Geofence(place.getName().toString(), latLng.latitude, latLng.longitude, preferences.getIntegerFromString(R.string.p_geofence_radius, 250));
Timber.i("Picked %s", geofence);
return geofence;
Location location = new Location();
location.setName(place.getName().toString());
location.setLatitude(latLng.latitude);
location.setLongitude(latLng.longitude);
location.setRadius(preferences.getIntegerFromString(R.string.p_geofence_radius, 250));
Timber.i("Picked %s", location);
return location;
}
}

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

@ -33,6 +33,8 @@ import org.tasks.R;
import org.tasks.backup.XmlWriter;
import org.tasks.data.Alarm;
import org.tasks.data.AlarmDao;
import org.tasks.data.Location;
import org.tasks.data.LocationDao;
import org.tasks.preferences.Preferences;
import org.xmlpull.v1.XmlSerializer;
@ -64,6 +66,7 @@ public class TasksXmlExporter {
private final TagDataDao tagDataDao;
private final MetadataDao metadataDao;
private final AlarmDao alarmDao;
private final LocationDao locationDao;
private final TaskDao taskDao;
private UserActivityDao userActivityDao;
private final Preferences preferences;
@ -94,13 +97,14 @@ public class TasksXmlExporter {
@Inject
public TasksXmlExporter(TagDataDao tagDataDao, MetadataDao metadataDao, TaskDao taskDao, UserActivityDao userActivityDao,
Preferences preferences, AlarmDao alarmDao) {
Preferences preferences, AlarmDao alarmDao, LocationDao locationDao) {
this.tagDataDao = tagDataDao;
this.metadataDao = metadataDao;
this.taskDao = taskDao;
this.userActivityDao = userActivityDao;
this.preferences = preferences;
this.alarmDao = alarmDao;
this.locationDao = locationDao;
}
public void exportTasks(final Context context, final ExportType exportType, @Nullable final ProgressDialog progressDialog) {
@ -188,7 +192,6 @@ 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++;
@ -221,9 +224,6 @@ public class TasksXmlExporter {
throw new RuntimeException(e);
}
}
}
private synchronized void serializeAlarms(Task task) {
for (Alarm alarm : alarmDao.getAlarms(task.getId())) {
try {
xml.startTag(null, BackupConstants.ALARM_TAG);
@ -233,6 +233,15 @@ public class TasksXmlExporter {
throw new RuntimeException(e);
}
}
for (Location location : locationDao.getGeofences(task.getId())) {
try {
xml.startTag(null, BackupConstants.LOCATION_TAG);
location.writeToXml(new XmlWriter(xml));
xml.endTag(null, BackupConstants.LOCATION_TAG);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/**

@ -34,6 +34,8 @@ import org.tasks.R;
import org.tasks.backup.XmlReader;
import org.tasks.data.Alarm;
import org.tasks.data.AlarmDao;
import org.tasks.data.LocationDao;
import org.tasks.data.Location;
import org.tasks.dialogs.DialogBuilder;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@ -56,6 +58,7 @@ public class TasksXmlImporter {
private final TaskDao taskDao;
private LocalBroadcastManager localBroadcastManager;
private final AlarmDao alarmDao;
private final LocationDao locationDao;
private Activity activity;
private Handler handler;
@ -72,13 +75,14 @@ public class TasksXmlImporter {
@Inject
public TasksXmlImporter(TagDataDao tagDataDao, MetadataDao metadataDao, UserActivityDao userActivityDao,
DialogBuilder dialogBuilder, TaskDao taskDao,
DialogBuilder dialogBuilder, TaskDao taskDao, LocationDao locationDao,
LocalBroadcastManager localBroadcastManager, AlarmDao alarmDao) {
this.tagDataDao = tagDataDao;
this.metadataDao = metadataDao;
this.userActivityDao = userActivityDao;
this.dialogBuilder = dialogBuilder;
this.taskDao = taskDao;
this.locationDao = locationDao;
this.localBroadcastManager = localBroadcastManager;
this.alarmDao = alarmDao;
}
@ -245,6 +249,16 @@ public class TasksXmlImporter {
alarmDao.insert(alarm);
}
void parseLocation() {
if (!currentTask.isSaved()) {
return;
}
Location location = new Location(new XmlReader(xpp));
locationDao.insert(location);
}
void parseMetadata(int format) {
if(!currentTask.isSaved()) {
return;
@ -381,6 +395,9 @@ public class TasksXmlImporter {
case BackupConstants.ALARM_TAG:
parseAlarm();
break;
case BackupConstants.LOCATION_TAG:
parseLocation();
break;
}
} catch (Exception e) {
errorCount++;

@ -25,6 +25,8 @@ import com.todoroo.astrid.data.UserActivity;
import org.tasks.data.Alarm;
import org.tasks.data.AlarmDao;
import org.tasks.data.Location;
import org.tasks.data.LocationDao;
import org.tasks.notifications.Notification;
import org.tasks.notifications.NotificationDao;
@ -48,9 +50,10 @@ import timber.log.Timber;
StoreObject.class,
Task.class,
Metadata.class,
Alarm.class
Alarm.class,
Location.class
},
version = 47)
version = 48)
public abstract class Database extends RoomDatabase {
public abstract NotificationDao notificationDao();
@ -60,6 +63,7 @@ public abstract class Database extends RoomDatabase {
public abstract TaskListMetadataDao getTaskListMetadataDao();
public abstract StoreObjectDao getStoreObjectDao();
public abstract AlarmDao getAlarmDao();
public abstract LocationDao getGeofenceDao();
public static final String NAME = "database";

@ -1,7 +0,0 @@
package com.todoroo.astrid.service;
import com.todoroo.astrid.data.Metadata;
public interface SynchronizeMetadataCallback {
void beforeDeleteMetadata(Metadata m);
}

@ -24,16 +24,15 @@ import android.widget.TextView;
import com.google.common.primitives.Longs;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.alarms.AlarmService;
import com.todoroo.astrid.data.Metadata;
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.data.Location;
import org.tasks.injection.ForActivity;
import org.tasks.injection.FragmentComponent;
import org.tasks.location.Geofence;
import org.tasks.location.GeofenceService;
import org.tasks.location.PlacePicker;
import org.tasks.preferences.Device;
@ -102,7 +101,7 @@ public class ReminderControlSet extends TaskEditControlFragment {
private final List<String> spinnerOptions = new ArrayList<>();
private ArrayAdapter<String> remindAdapter;
private final Set<Long> alarms = new LinkedHashSet<>();
private final Set<Geofence> geofences = new LinkedHashSet<>();
private final Set<Location> locations = new LinkedHashSet<>();
@OnItemSelected(R.id.reminder_alarm)
void ringModeSelected(int position) {
@ -124,12 +123,12 @@ public class ReminderControlSet extends TaskEditControlFragment {
taskId = savedInstanceState.getLong(EXTRA_TASK_ID);
flags = savedInstanceState.getInt(EXTRA_FLAGS);
randomReminder = savedInstanceState.getLong(EXTRA_RANDOM_REMINDER);
List<Geofence> geofences = new ArrayList<>();
List<Location> locations = new ArrayList<>();
List<Parcelable> geofenceArray = savedInstanceState.getParcelableArrayList(EXTRA_GEOFENCES);
for (Parcelable geofence : geofenceArray) {
geofences.add((Geofence) geofence);
locations.add((Location) geofence);
}
setup(Longs.asList(savedInstanceState.getLongArray(EXTRA_ALARMS)), geofences);
setup(Longs.asList(savedInstanceState.getLongArray(EXTRA_ALARMS)), locations);
} else {
setup(currentAlarms(), geofenceService.getGeofences(taskId));
}
@ -199,7 +198,7 @@ public class ReminderControlSet extends TaskEditControlFragment {
randomReminder = task.getReminderPeriod();
}
private void setup(List<Long> alarms, List<Geofence> geofences) {
private void setup(List<Long> alarms, List<Location> locations) {
setValue(flags);
alertContainer.removeAllViews();
@ -215,8 +214,8 @@ public class ReminderControlSet extends TaskEditControlFragment {
for (long timestamp : alarms) {
addAlarmRow(timestamp);
}
for (Geofence geofence : geofences) {
addGeolocationReminder(geofence);
for (Location location : locations) {
addGeolocationReminder(location);
}
updateSpinner();
}
@ -226,7 +225,7 @@ public class ReminderControlSet extends TaskEditControlFragment {
return getFlags() != original.getReminderFlags() ||
getRandomReminderPeriod() != original.getReminderPeriod() ||
!newHashSet(currentAlarms()).equals(alarms) ||
!newHashSet(geofenceService.getGeofences(taskId)).equals(geofences);
!newHashSet(geofenceService.getGeofences(taskId)).equals(locations);
}
@Override
@ -238,7 +237,7 @@ public class ReminderControlSet extends TaskEditControlFragment {
if(alarmService.synchronizeAlarms(task.getId(), alarms)) {
task.setModificationDate(DateUtilities.now());
}
if (geofenceService.synchronizeGeofences(task.getId(), geofences)) {
if (geofenceService.synchronizeGeofences(task.getId(), locations)) {
task.setModificationDate(DateUtilities.now());
}
}
@ -251,7 +250,7 @@ public class ReminderControlSet extends TaskEditControlFragment {
outState.putInt(EXTRA_FLAGS, getFlags());
outState.putLong(EXTRA_RANDOM_REMINDER, getRandomReminderPeriod());
outState.putLongArray(EXTRA_ALARMS, Longs.toArray(alarms));
outState.putParcelableArrayList(EXTRA_GEOFENCES, newArrayList(geofences));
outState.putParcelableArrayList(EXTRA_GEOFENCES, newArrayList(locations));
}
@Override
@ -292,9 +291,9 @@ public class ReminderControlSet extends TaskEditControlFragment {
}
}
private void addGeolocationReminder(final Geofence geofence) {
addAlarmRow(geofence.getName(), v -> geofences.remove(geofence));
geofences.add(geofence);
private void addGeolocationReminder(final Location location) {
addAlarmRow(location.getName(), v -> locations.remove(location));
locations.add(location);
}
private int getFlags() {

@ -38,4 +38,12 @@ public class XmlReader {
writer.write(value);
}
}
public void readDouble(String name, ValueWriter<Double> writer) {
String value = xpp.getAttributeValue(null, name);
if (value != null) {
writer.write(TasksXmlExporter.XML_NULL.equals(value) ?
null : Double.parseDouble(value));
}
}
}

@ -51,4 +51,16 @@ public class XmlWriter {
throw new RuntimeException(e);
}
}
public void writeDouble(String name, Double value) {
try {
String valueString = (value == null) ? XML_NULL : value.toString();
xml.attribute(null, name, valueString);
} catch (UnsupportedOperationException e) {
// didn't read this value, do nothing
Timber.e(e, e.getMessage());
} catch (IllegalArgumentException | IllegalStateException | IOException e) {
throw new RuntimeException(e);
}
}
}

@ -0,0 +1,181 @@
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 android.os.Parcel;
import android.os.Parcelable;
import org.tasks.backup.XmlReader;
import org.tasks.backup.XmlWriter;
import java.io.Serializable;
@Entity(tableName = "locations")
public class Location implements Serializable, Parcelable {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "_id")
private long id;
@ColumnInfo(name = "task")
private long task;
@ColumnInfo(name = "name")
private String name;
@ColumnInfo(name = "latitude")
private double latitude;
@ColumnInfo(name = "longitude")
private double longitude;
@ColumnInfo(name = "radius")
private int radius;
public Location() {
}
@Ignore
public Location(Parcel parcel) {
id = parcel.readLong();
task = parcel.readLong();
name = parcel.readString();
latitude = parcel.readDouble();
longitude = parcel.readDouble();
radius = parcel.readInt();
}
@Ignore
public Location(XmlReader xml) {
xml.readLong("task", this::setTask);
xml.readString("name", this::setName);
xml.readDouble("latitude", this::setLatitude);
xml.readDouble("longitude", this::setLongitude);
xml.readInteger("radius", this::setRadius);
}
public void writeToXml(XmlWriter xmlWriter) {
xmlWriter.writeLong("task", task);
xmlWriter.writeString("name", name);
xmlWriter.writeDouble("latitude", latitude);
xmlWriter.writeDouble("longitude", longitude);
xmlWriter.writeInteger("radius", radius);
}
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 String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public int getRadius() {
return radius;
}
public void setRadius(int radius) {
this.radius = radius;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Location location = (Location) o;
if (id != location.id) return false;
if (task != location.task) return false;
if (Double.compare(location.latitude, latitude) != 0) return false;
if (Double.compare(location.longitude, longitude) != 0) return false;
if (radius != location.radius) return false;
return name != null ? name.equals(location.name) : location.name == null;
}
@Override
public int hashCode() {
int result;
long temp;
result = (int) (id ^ (id >>> 32));
result = 31 * result + (int) (task ^ (task >>> 32));
result = 31 * result + (name != null ? name.hashCode() : 0);
temp = Double.doubleToLongBits(latitude);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(longitude);
result = 31 * result + (int) (temp ^ (temp >>> 32));
result = 31 * result + radius;
return result;
}
@Override
public String toString() {
return "Location{" +
"id=" + id +
", task=" + task +
", name='" + name + '\'' +
", latitude=" + latitude +
", longitude=" + longitude +
", radius=" + radius +
'}';
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeLong(id);
out.writeLong(task);
out.writeString(name);
out.writeDouble(latitude);
out.writeDouble(longitude);
out.writeInt(radius);
}
public static final Parcelable.Creator<Location> CREATOR = new Parcelable.Creator<Location>() {
@Override
public Location createFromParcel(Parcel source) {
return new Location(source);
}
@Override
public Location[] newArray(int size) {
return new Location[size];
}
};
}

@ -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 LocationDao {
@Query("SELECT * FROM locations WHERE _id = :id LIMIT 1")
Location getGeofence(Long id);
@Query("SELECT * FROM locations WHERE task = :taskId ORDER BY name ASC")
List<Location> getGeofences(long taskId);
@Query("SELECT locations.* FROM locations LEFT JOIN tasks ON tasks._id = locations.task WHERE locations.task = :taskId AND tasks.deleted = 0 AND tasks.completed = 0")
List<Location> getActiveGeofences(long taskId);
@Query("SELECT locations.* FROM locations LEFT JOIN tasks ON tasks._id = locations.task WHERE tasks.deleted = 0 AND tasks.completed = 0")
List<Location> getActiveGeofences();
@Delete
void delete(Location location);
@Insert
void insert(Location location);
}

@ -43,6 +43,16 @@ public class Migrations {
}
};
private static final Migration MIGRATION_47_48 = new Migration(47, 48) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE IF NOT EXISTS `locations` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `task` INTEGER NOT NULL, `name` TEXT, `latitude` REAL NOT NULL, `longitude` REAL NOT NULL, `radius` INTEGER NOT NULL)");
database.execSQL("INSERT INTO `locations` (`task`, `name`, `latitude`, `longitude`, `radius`) " +
"SELECT `task`, `value`, `value2`, `value3`, `value4` FROM `metadata` WHERE `key` = 'geofence'");
database.execSQL("DELETE FROM `metadata` WHERE `key` = 'geofence'");
}
};
private static Migration NOOP(int from, int to) {
return new Migration(from, to) {
@Override
@ -64,6 +74,7 @@ public class Migrations {
NOOP(43, 44),
NOOP(44, 45),
NOOP(45, 46),
MIGRATION_46_47
MIGRATION_46_47,
MIGRATION_47_48
};
}

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

@ -1,133 +0,0 @@
package org.tasks.location;
import android.os.Parcel;
import android.os.Parcelable;
import com.todoroo.astrid.data.Metadata;
import java.io.Serializable;
public class Geofence implements Serializable, Parcelable {
private final String name;
private final double latitude;
private final double longitude;
private final int radius;
private long taskId;
private long metadataId;
public Geofence(Metadata metadata) {
this(metadata.getValue(GeofenceFields.PLACE),
metadata.getValue(GeofenceFields.LATITUDE),
metadata.getValue(GeofenceFields.LONGITUDE),
metadata.getValue(GeofenceFields.RADIUS));
metadataId = metadata.getId();
taskId = metadata.getTask();
}
public Geofence(String name, double latitude, double longitude, int radius) {
this.name = name;
this.latitude = latitude;
this.longitude = longitude;
this.radius = radius;
}
public Metadata toMetadata() {
Metadata metadata = new Metadata();
metadata.setKey(GeofenceFields.METADATA_KEY);
metadata.setValue(GeofenceFields.PLACE, name);
metadata.setValue(GeofenceFields.LATITUDE, latitude);
metadata.setValue(GeofenceFields.LONGITUDE, longitude);
metadata.setValue(GeofenceFields.RADIUS, radius);
return metadata;
}
public String getName() {
return name;
}
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
public long getMetadataId() {
return metadataId;
}
public long getTaskId() {
return taskId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Geofence geofence = (Geofence) o;
if (Double.compare(geofence.latitude, latitude) != 0) return false;
if (Double.compare(geofence.longitude, longitude) != 0) return false;
if (radius != geofence.radius) return false;
if (taskId != geofence.taskId) return false;
if (metadataId != geofence.metadataId) return false;
return !(name != null ? !name.equals(geofence.name) : geofence.name != null);
}
@Override
public int hashCode() {
int result;
long temp;
result = name != null ? name.hashCode() : 0;
temp = Double.doubleToLongBits(latitude);
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(longitude);
result = 31 * result + (int) (temp ^ (temp >>> 32));
result = 31 * result + radius;
result = 31 * result + (int) (taskId ^ (taskId >>> 32));
result = 31 * result + (int) (metadataId ^ (metadataId >>> 32));
return result;
}
@Override
public String toString() {
return "Geofence{" +
"name='" + name + '\'' +
", latitude=" + latitude +
", longitude=" + longitude +
", radius=" + radius +
", taskId=" + taskId +
", metadataId=" + metadataId +
'}';
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(name);
out.writeDouble(latitude);
out.writeDouble(longitude);
out.writeInt(radius);
}
public static final Parcelable.Creator<Geofence> CREATOR = new Parcelable.Creator<Geofence>() {
@Override
public Geofence createFromParcel(Parcel source) {
String name = source.readString();
double latitude = source.readDouble();
double longitude = source.readDouble();
int radius = source.readInt();
return new Geofence(name, latitude, longitude, radius);
}
@Override
public Geofence[] newArray(int size) {
return new Geofence[size];
}
};
}

@ -1,24 +0,0 @@
package org.tasks.location;
import com.todoroo.andlib.data.Property.IntegerProperty;
import com.todoroo.astrid.data.Metadata;
import static com.todoroo.andlib.data.Property.DoubleProperty;
import static com.todoroo.andlib.data.Property.StringProperty;
class GeofenceFields {
public static final String METADATA_KEY = "geofence";
public static final StringProperty PLACE = new StringProperty(Metadata.TABLE,
Metadata.VALUE1.name);
public static final DoubleProperty LATITUDE = new DoubleProperty(Metadata.TABLE,
Metadata.VALUE2.name);
public static final DoubleProperty LONGITUDE = new DoubleProperty(Metadata.TABLE,
Metadata.VALUE3.name);
public static final IntegerProperty RADIUS = new IntegerProperty(Metadata.TABLE,
Metadata.VALUE4.name);
}

@ -1,44 +1,28 @@
package org.tasks.location;
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 java.util.HashSet;
import org.tasks.data.Location;
import org.tasks.data.LocationDao;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Lists.newArrayList;
public class GeofenceService {
private final MetadataDao metadataDao;
private final GeofenceApi geofenceApi;
private final LocationDao locationDao;
@Inject
public GeofenceService(MetadataDao metadataDao, GeofenceApi geofenceApi) {
this.metadataDao = metadataDao;
public GeofenceService(GeofenceApi geofenceApi, LocationDao locationDao) {
this.geofenceApi = geofenceApi;
this.locationDao = locationDao;
}
public List<Geofence> getGeofences(long taskId) {
return toGeofences(metadataDao.toList(Query.select(
Metadata.PROPERTIES).where(MetadataCriteria.byTaskAndwithKey(
taskId, GeofenceFields.METADATA_KEY)).orderBy(Order.asc(GeofenceFields.PLACE))));
public List<Location> getGeofences(long taskId) {
return locationDao.getGeofences(taskId);
}
public void setupGeofences() {
@ -54,87 +38,65 @@ public class GeofenceService {
}
public void cancelGeofences(long taskId) {
for (Geofence geofence : getGeofences(taskId)) {
geofenceApi.cancel(geofence);
for (Location location : getGeofences(taskId)) {
geofenceApi.cancel(location);
}
}
public boolean synchronizeGeofences(final long taskId, Set<Geofence> geofences) {
List<Metadata> metadatas = newArrayList(transform(geofences, Geofence::toMetadata));
boolean changed = synchronizeMetadata(taskId, metadatas, m -> geofenceApi.cancel(new Geofence(m)));
public boolean synchronizeGeofences(final long taskId, Set<Location> locations) {
boolean changed = synchronizeMetadata(taskId, newArrayList(locations), geofenceApi::cancel);
if(changed) {
setupGeofences(taskId);
}
return changed;
}
private List<Geofence> toGeofences(List<Metadata> geofences) {
return newArrayList(transform(geofences, Geofence::new));
private List<Location> getActiveGeofences() {
return locationDao.getActiveGeofences();
}
private List<Geofence> getActiveGeofences() {
return toGeofences(metadataDao.toList(Query.select(Metadata.ID, Metadata.TASK, GeofenceFields.PLACE, GeofenceFields.LATITUDE, GeofenceFields.LONGITUDE, GeofenceFields.RADIUS).
join(Join.inner(Task.TABLE, Metadata.TASK.eq(Task.ID))).
where(Criterion.and(TaskCriteria.isActive(), MetadataCriteria.withKey(GeofenceFields.METADATA_KEY)))));
private List<Location> getGeofencesForTask(long taskId) {
return locationDao.getActiveGeofences(taskId);
}
private List<Geofence> getGeofencesForTask(long taskId) {
return toGeofences(metadataDao.toList(Query.select(Metadata.ID, Metadata.TASK, GeofenceFields.PLACE, GeofenceFields.LATITUDE, GeofenceFields.LONGITUDE, GeofenceFields.RADIUS).
join(Join.inner(Task.TABLE, Metadata.TASK.eq(Task.ID))).
where(Criterion.and(TaskCriteria.isActive(),
MetadataCriteria.byTaskAndwithKey(taskId, GeofenceFields.METADATA_KEY)))));
public interface SynchronizeGeofenceCallback {
void beforeDelete(Location location);
}
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) {
private boolean synchronizeMetadata(long taskId, List<Location> locations, final SynchronizeGeofenceCallback callback) {
boolean dirty = false;
for(Location metadatum : locations) {
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, GeofenceFields.METADATA_KEY)) {
for (Location item : locationDao.getGeofences(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();
item.setId(0L);
if(newMetadataValues.contains(itemMergedValues)) {
newMetadataValues.remove(itemMergedValues);
if(locations.contains(item)) {
locations.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;
locationDao.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(Location location : locations) {
locationDao.insert(location);
dirty = true;
}
return dirty[0];
return dirty;
}
}

Loading…
Cancel
Save