Serialization with GSON

gtask_note_sync
Bernhard Mähr 7 years ago
parent d46bbd4d2c
commit 6de789f473

@ -145,6 +145,7 @@ dependencies {
googleplayCompile "com.google.android.gms:play-services-places:${GPS_VERSION}"
googleplayCompile 'com.google.apis:google-api-services-tasks:v1-rev46-1.22.0'
googleplayCompile 'com.google.api-client:google-api-client-android:1.22.0'
googleplayCompile 'com.google.code.gson:gson:2.8.0'
amazonCompile "com.google.android.gms:play-services-analytics:${GPS_VERSION}"

@ -19,6 +19,7 @@ import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mockito;
import org.tasks.R;
import org.tasks.injection.ApplicationComponent;
@ -41,6 +42,11 @@ import static junit.framework.Assert.assertEquals;
@RunWith(AndroidJUnit4.class)
public class GoogleTaskSyncNoteAdapterTest {
private static int DEFAULT_WRITE_IMPORTANCE = Task.IMPORTANCE_SHOULD_DO;
private static int DEFAULT_WRITE_REMINDER_FLAGS = Task.NOTIFY_AT_DEADLINE | Task.NOTIFY_AFTER_DEADLINE;
private static int DEFAULT_READ_IMPORTANCE = Task.IMPORTANCE_SHOULD_DO;
private static int DEFAULT_READ_REMINDER_FLAGS = Task.NOTIFY_AT_DEADLINE | Task.NOTIFY_AFTER_DEADLINE;
private GoogleTaskSyncAdapter adapter;
private TagDataDao tagDataDao;
private Task task;
@ -51,6 +57,8 @@ public class GoogleTaskSyncNoteAdapterTest {
private String enhancedNotes;
private boolean enableNoteMetadataSync = true;
@Before
public void setup() {
SyncAdapterComponent syncAdapterComponent = Mockito.mock(SyncAdapterComponent.class);
@ -64,7 +72,8 @@ public class GoogleTaskSyncNoteAdapterTest {
Preferences preferences = Mockito.mock(Preferences.class);
Mockito.when(preferences.getIntegerFromString(R.string.p_default_importance_key, Task.IMPORTANCE_SHOULD_DO)).thenReturn(Task.IMPORTANCE_SHOULD_DO);
Mockito.when(preferences.getIntegerFromString(Matchers.eq(R.string.p_default_importance_key), Mockito.anyInt())).thenReturn(DEFAULT_WRITE_IMPORTANCE);
Mockito.when(preferences.getIntegerFromString(Matchers.eq(R.string.p_default_reminders_key), Mockito.anyInt())).thenReturn(DEFAULT_WRITE_REMINDER_FLAGS);
adapter.preferences = preferences;
GtasksPreferenceService gtasksPreferenceService = new GtasksPreferenceService(preferences) {
public boolean getUseNoteForMetadataSync() {
@ -101,7 +110,8 @@ public class GoogleTaskSyncNoteAdapterTest {
task = new Task();
task.setImportance(Task.IMPORTANCE_SHOULD_DO);
task.setImportance(DEFAULT_WRITE_IMPORTANCE);
task.setReminderFlags(DEFAULT_WRITE_REMINDER_FLAGS);
remoteModel = new com.google.api.services.tasks.model.Task();
remoteModel.setNotes(null);
@ -195,7 +205,7 @@ public class GoogleTaskSyncNoteAdapterTest {
addTag("test");
adapter.writeNotesIfNecessary(task, remoteModel);
enhancedNotes = remoteModel.getNotes();
Assert.assertEquals("xxx" + GoogleTaskSyncAdapter.LINE_FEED + "" + GoogleTaskSyncAdapter.LINE_FEED + "{tasks-tags:test}", enhancedNotes);
Assert.assertEquals("xxx" + GoogleTaskSyncAdapter.LINE_FEED + "" + GoogleTaskSyncAdapter.LINE_FEED + "{tasks:additionalMetadata{\"tags\":[\"test\"]}}", enhancedNotes);
}
@Test
@ -203,7 +213,7 @@ public class GoogleTaskSyncNoteAdapterTest {
addTag("test");
adapter.writeNotesIfNecessary(task, remoteModel);
enhancedNotes = remoteModel.getNotes();
Assert.assertEquals(GoogleTaskSyncAdapter.LINE_FEED + GoogleTaskSyncAdapter.LINE_FEED + "{tasks-tags:test}", enhancedNotes);
Assert.assertEquals(GoogleTaskSyncAdapter.LINE_FEED + GoogleTaskSyncAdapter.LINE_FEED + "{tasks:additionalMetadata{\"tags\":[\"test\"]}}", enhancedNotes);
}
@ -213,16 +223,16 @@ public class GoogleTaskSyncNoteAdapterTest {
task.setHideUntil(0l);
adapter.writeNotesIfNecessary(task, remoteModel);
enhancedNotes = remoteModel.getNotes();
Assert.assertEquals(GoogleTaskSyncAdapter.LINE_FEED + GoogleTaskSyncAdapter.LINE_FEED + "{tasks-tags:test}", enhancedNotes);
Assert.assertEquals(GoogleTaskSyncAdapter.LINE_FEED + GoogleTaskSyncAdapter.LINE_FEED + "{tasks:additionalMetadata{\"tags\":[\"test\"]}}", enhancedNotes);
}
@Test
public void testStoreMetadataImportanceDefault() {
addTag("test");
task.setImportance(Task.IMPORTANCE_SHOULD_DO);
task.setImportance(DEFAULT_WRITE_IMPORTANCE);
adapter.writeNotesIfNecessary(task, remoteModel);
enhancedNotes = remoteModel.getNotes();
Assert.assertEquals(GoogleTaskSyncAdapter.LINE_FEED + GoogleTaskSyncAdapter.LINE_FEED + "{tasks-tags:test}", enhancedNotes);
Assert.assertEquals(GoogleTaskSyncAdapter.LINE_FEED + GoogleTaskSyncAdapter.LINE_FEED + "{tasks:additionalMetadata{\"tags\":[\"test\"]}}", enhancedNotes);
}
@Test
@ -231,9 +241,26 @@ public class GoogleTaskSyncNoteAdapterTest {
task.setImportance(Task.IMPORTANCE_NONE);
adapter.writeNotesIfNecessary(task, remoteModel);
enhancedNotes = remoteModel.getNotes();
Assert.assertEquals(GoogleTaskSyncAdapter.LINE_FEED + GoogleTaskSyncAdapter.LINE_FEED + "{tasks-tags:test}" + GoogleTaskSyncAdapter.LINE_FEED + "{tasks-prio:LOW}", enhancedNotes);
Assert.assertEquals(GoogleTaskSyncAdapter.LINE_FEED + GoogleTaskSyncAdapter.LINE_FEED + "{tasks:additionalMetadata{\"importance\":\"LOW\",\"tags\":[\"test\"]}}", enhancedNotes);
}
@Test
public void testStoreMetadataReminderNone() {
addTag("test");
task.setReminderFlags(0);
adapter.writeNotesIfNecessary(task, remoteModel);
enhancedNotes = remoteModel.getNotes();
Assert.assertEquals(GoogleTaskSyncAdapter.LINE_FEED + GoogleTaskSyncAdapter.LINE_FEED + "{tasks:additionalMetadata{\"notifyAfterDeadline\":false,\"notifyAtDeadline\":false,\"tags\":[\"test\"]}}", enhancedNotes);
}
@Test
public void testStoreMetadataReminderDefault() {
addTag("test");
task.setReminderFlags(DEFAULT_WRITE_REMINDER_FLAGS);
adapter.writeNotesIfNecessary(task, remoteModel);
enhancedNotes = remoteModel.getNotes();
Assert.assertEquals(GoogleTaskSyncAdapter.LINE_FEED + GoogleTaskSyncAdapter.LINE_FEED + "{tasks:additionalMetadata{\"tags\":[\"test\"]}}", enhancedNotes);
}
@Test
public void testStoreMetadataToNoteAll() {
@ -253,7 +280,7 @@ public class GoogleTaskSyncNoteAdapterTest {
task.setImportance(Task.IMPORTANCE_DO_OR_DIE);
adapter.writeNotesIfNecessary(task, remoteModel);
enhancedNotes = remoteModel.getNotes();
Assert.assertEquals("xxx" + GoogleTaskSyncAdapter.LINE_FEED + "" + GoogleTaskSyncAdapter.LINE_FEED + "{tasks-tags:test3;test2;test}" + GoogleTaskSyncAdapter.LINE_FEED + "{tasks-prio:MUST}" + GoogleTaskSyncAdapter.LINE_FEED + "{tasks-hide:1970-01-13T20:38:31.111Z}" + GoogleTaskSyncAdapter.LINE_FEED + "{tasks-remind:at;after;five}" + GoogleTaskSyncAdapter.LINE_FEED + "{tasks-recur:RRULE:FREQ=MONTHLY;INTERVAL=1;1970-01-02T10:17:36.789Z}", enhancedNotes);
Assert.assertEquals("xxx" + GoogleTaskSyncAdapter.LINE_FEED + "" + GoogleTaskSyncAdapter.LINE_FEED + "{tasks:additionalMetadata{\"hideUntil\":\"1970-01-13T20:38:31\",\"importance\":\"MUST\",\"notifyModeFive\":true,\"recurrence\":\"RRULE:FREQ\\u003dMONTHLY;INTERVAL\\u003d1\",\"repeatUntil\":\"1970-01-02T10:17:36\",\"tags\":[\"test\",\"test2\",\"test3\"]}}", enhancedNotes);
}
@Test
@ -273,7 +300,7 @@ public class GoogleTaskSyncNoteAdapterTest {
addTag("test");
adapter.writeNotesIfNecessary(task, remoteModel);
enhancedNotes = remoteModel.getNotes();
Assert.assertEquals("xxx" + GoogleTaskSyncAdapter.LINE_FEED + "" + GoogleTaskSyncAdapter.LINE_FEED + "{tasks-tags:test3;test2;test}", enhancedNotes);
Assert.assertEquals("xxx" + GoogleTaskSyncAdapter.LINE_FEED + "" + GoogleTaskSyncAdapter.LINE_FEED + "{tasks:additionalMetadata{\"tags\":[\"test\",\"test2\",\"test3\"]}}", enhancedNotes);
}
@Test
@ -311,18 +338,19 @@ public class GoogleTaskSyncNoteAdapterTest {
public void testReadMetadataImportanceDefault() {
testStoreMetadataImportanceDefault();
task = new Task();
task.setImportance(Task.IMPORTANCE_DO_OR_DIE);
task.setImportance(DEFAULT_READ_IMPORTANCE);
task.setNotes(enhancedNotes);
adapter.processNotes(task);
Assert.assertEquals("", task.getNotes());
Assert.assertTrue(persistedTags.contains("test"));
Assert.assertEquals(Task.IMPORTANCE_DO_OR_DIE, (int)task.getImportance());
Assert.assertEquals(DEFAULT_READ_IMPORTANCE, (int)task.getImportance());
}
@Test
public void testReadMetadataImportanceLow() {
testStoreMetadataImportanceLow();
task = new Task();
task.setImportance(DEFAULT_READ_IMPORTANCE);
task.setNotes(enhancedNotes);
adapter.processNotes(task);
Assert.assertEquals("", task.getNotes());
@ -330,6 +358,31 @@ public class GoogleTaskSyncNoteAdapterTest {
Assert.assertEquals(Task.IMPORTANCE_NONE, (int)task.getImportance());
}
@Test
public void testReadMetadataReminderDefault() {
testStoreMetadataReminderDefault();
task = new Task();
task.setReminderFlags(DEFAULT_READ_REMINDER_FLAGS);
task.setNotes(enhancedNotes);
adapter.processNotes(task);
Assert.assertEquals("", task.getNotes());
Assert.assertTrue(persistedTags.contains("test"));
Assert.assertEquals(DEFAULT_READ_REMINDER_FLAGS, (int)task.getReminderFlags());
}
@Test
public void testReadMetadataReminderNone() {
testStoreMetadataReminderNone();
task = new Task();
task.setReminderFlags(DEFAULT_WRITE_REMINDER_FLAGS);
task.setNotes(enhancedNotes);
adapter.processNotes(task);
Assert.assertEquals("", task.getNotes());
Assert.assertTrue(persistedTags.contains("test"));
Assert.assertEquals(0, (int)task.getReminderFlags());
}
@Test
public void testReadMetadataFromNoteAll() {
@ -342,16 +395,16 @@ public class GoogleTaskSyncNoteAdapterTest {
Assert.assertTrue(persistedTags.contains("test"));
Assert.assertTrue(persistedTags.contains("test2"));
Assert.assertTrue(persistedTags.contains("test3"));
Assert.assertEquals(Task.NOTIFY_AT_DEADLINE | Task.NOTIFY_AFTER_DEADLINE | Task.NOTIFY_MODE_NONSTOP | Task.NOTIFY_MODE_FIVE, (int)task.getReminderFlags());
Assert.assertEquals(Task.NOTIFY_AT_DEADLINE | Task.NOTIFY_AFTER_DEADLINE | Task.NOTIFY_MODE_FIVE, (int)task.getReminderFlags());
Assert.assertEquals("RRULE:FREQ=MONTHLY;INTERVAL=1", task.getRecurrence());
Assert.assertEquals(123456789l, (long)task.getRepeatUntil());
Assert.assertEquals(1111111111l, (long)task.getHideUntil());
Assert.assertEquals(123456000l, (long)task.getRepeatUntil());
Assert.assertEquals(1111111000l, (long)task.getHideUntil());
Assert.assertEquals(Task.IMPORTANCE_DO_OR_DIE, (long)task.getImportance());
}
@Test
public void testReadMetadataFromNoteRecurrenceWithoutRepeatUntil() {
enhancedNotes = "xxx" + GoogleTaskSyncAdapter.LINE_FEED + "" + GoogleTaskSyncAdapter.LINE_FEED + "{tasks-recur:RRULE:FREQ=MONTHLY;INTERVAL=1}";
enhancedNotes = "xxx" + GoogleTaskSyncAdapter.LINE_FEED + "" + GoogleTaskSyncAdapter.LINE_FEED + "{tasks:additionalMetadata{\"recurrence\":\"RRULE:FREQ=MONTHLY;INTERVAL=1\"}}";
task = new Task();
task.setNotes(enhancedNotes);
adapter.processNotes(task);
@ -360,4 +413,15 @@ public class GoogleTaskSyncNoteAdapterTest {
Assert.assertEquals(0, (long)task.getRepeatUntil());
}
@Test
public void testReadMetadataFromNoteCorruptJSON() {
enhancedNotes = "xxx" + GoogleTaskSyncAdapter.LINE_FEED + "" + GoogleTaskSyncAdapter.LINE_FEED + "{tasks:additionalMetadata{\"recurrence\":\"}}";
task = new Task();
task.setNotes(enhancedNotes);
adapter.processNotes(task);
Assert.assertEquals("xxx", task.getNotes());
Assert.assertEquals("", task.getRecurrence());
Assert.assertEquals(0, (long)task.getRepeatUntil());
}
}

@ -5,33 +5,14 @@
*/
package com.todoroo.astrid.gtasks.api;
import com.google.api.client.googleapis.testing.json.GoogleJsonResponseExceptionFactoryTesting;
import com.google.api.client.util.DateTime;
import com.todoroo.astrid.data.Task;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import timber.log.Timber;
public class GtasksApiUtilities {
public static final char NOTE_METADATA_VALUE_SPLIT_CHAR = ';';
private static final String REMINDER_FLAG_AT = "at";
private static final String REMINDER_FLAG_AFTER = "after";
private static final String REMINDER_FLAG_FIVE = "five";
private static final String REMINDER_FLAG_NONSTOP = "nonstop";
private static Map<String, Integer> importanceMapping;
public static DateTime unixTimeToGtasksCompletionTime(long time) {
if (time < 0) {
return null;
@ -80,108 +61,18 @@ public class GtasksApiUtilities {
}
}
public static String unixTimeToGtasksStringTime(long time) {
public static Date unixTimeToDateTime(long time) {
if (time <= 0) {
return null;
}
DateTime dateTime = new DateTime(new Date(time), TimeZone.getDefault());
return dateTime.toStringRfc3339();
return new Date(time);
}
public static long gtasksStringTimeToUnixTime(String gtasksStringTime) {
if (gtasksStringTime == null || gtasksStringTime.trim().length()==0) {
return 0;
}
try {
DateTime dateTime = DateTime.parseRfc3339(gtasksStringTime);
return dateTime.getValue();
} catch (NumberFormatException e) {
Timber.e(e, e.getMessage());
public static long dateTimeToUnixTime(Date dateTime) {
if (dateTime == null) {
return 0;
}
return dateTime.getTime();
}
public static Set<String> gtasksTagsToTags(String tagsString) {
String[] tags = tagsString.split("" + GtasksApiUtilities.NOTE_METADATA_VALUE_SPLIT_CHAR);
return new HashSet<String>(Arrays.asList(tags));
}
public static String tagsToGtaskTags(Collection<String> tags) {
if (tags!=null && tags.size()>0) {
StringBuffer buf = new StringBuffer();
for (String tag : tags) {
appendValue(buf, tag);
}
return buf.toString();
} else {
return null;
}
}
public static String importanceToGtasksString(int importance) {
String result = null;
for (Map.Entry<String, Integer> e : importanceMapping.entrySet()) {
if (result == null && Integer.valueOf(importance).equals(e.getValue())) {
result = e.getKey();
}
}
return result;
}
public static int gtasksStringToImportance(String importance, int defaultImportance) {
Integer result = importanceMapping.get(importance);
if (result==null) {
result = defaultImportance;
}
return result;
}
public static String reminderFlagsToGtasksString(boolean atDeadline, boolean afterDeadline, boolean nonstop, boolean modeFive) {
StringBuffer buf = new StringBuffer();
if (atDeadline) {
appendValue(buf, REMINDER_FLAG_AT);
}
if (afterDeadline) {
appendValue(buf, REMINDER_FLAG_AFTER);
}
if (modeFive) {
appendValue(buf, REMINDER_FLAG_FIVE);
} else if (nonstop) {
appendValue(buf, REMINDER_FLAG_NONSTOP);
}
return buf.toString();
}
public static int gtasksReminderFlagsTimeToFlags(String flags) {
List<String> reminderFlags = Arrays.asList(flags.split("" + GtasksApiUtilities.NOTE_METADATA_VALUE_SPLIT_CHAR));
int result = 0;
result = result | (reminderFlags.contains(REMINDER_FLAG_AT)?Task.NOTIFY_AT_DEADLINE:0);
result = result | (reminderFlags.contains(REMINDER_FLAG_AFTER)?Task.NOTIFY_AFTER_DEADLINE:0);
result = result | (reminderFlags.contains(REMINDER_FLAG_FIVE)?Task.NOTIFY_MODE_FIVE | Task.NOTIFY_MODE_NONSTOP :0);
result = result | (reminderFlags.contains(REMINDER_FLAG_NONSTOP)?Task.NOTIFY_MODE_NONSTOP:0);
return result;
}
// Helper
private static void appendValue(StringBuffer buf, String value) {
if (value!=null && value.trim().length()>0) {
if (buf.length() > 0) {
buf.append(NOTE_METADATA_VALUE_SPLIT_CHAR);
}
buf.append(value.trim());
}
}
static {
importanceMapping = new HashMap<>();
importanceMapping.put("MUST", Task.IMPORTANCE_DO_OR_DIE);
importanceMapping.put("HIGH", Task.IMPORTANCE_MUST_DO);
importanceMapping.put("DEFAULT", Task.IMPORTANCE_SHOULD_DO);
importanceMapping.put("LOW", Task.IMPORTANCE_NONE);
}
}

@ -0,0 +1,119 @@
package org.tasks.gtasks;
import com.todoroo.astrid.data.Task;
import java.util.Date;
import java.util.List;
public class GoogleTaskAdditionalMetadata {
public enum Importance {
MUST(Task.IMPORTANCE_DO_OR_DIE),
HIGH(Task.IMPORTANCE_MUST_DO),
DEFAULT(Task.IMPORTANCE_SHOULD_DO),
LOW(Task.IMPORTANCE_NONE);
private int taskImportance;
Importance(int taskImportance) {
this.taskImportance = taskImportance;
}
public int getTaskImportance() {
return taskImportance;
}
public static Importance valueOf(int taskImportance) {
Importance result = DEFAULT;
for(Importance i: values()) {
if (i.getTaskImportance()==taskImportance) {
result = i;
}
}
return result;
}
}
private List<String> tags;
private Importance importance;
private Date hideUntil;
private Boolean notifyAtDeadline;
private Boolean notifyAfterDeadline;
private Boolean notifyModeNonstop;
private Boolean notifyModeFive;
private Date repeatUntil;
private String recurrence;
public List<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags = tags;
}
public Importance getImportance() {
return importance;
}
public void setImportance(Importance importance) {
this.importance = importance;
}
public Date getHideUntil() {
return hideUntil;
}
public void setHideUntil(Date hideUntil) {
this.hideUntil = hideUntil;
}
public Boolean isNotifyAtDeadline() {
return notifyAtDeadline;
}
public void setNotifyAtDeadline(boolean notifyAtDeadline) {
this.notifyAtDeadline = notifyAtDeadline;
}
public Boolean isNotifyAfterDeadline() {
return notifyAfterDeadline;
}
public void setNotifyAfterDeadline(boolean notifyAfterDeadline) {
this.notifyAfterDeadline = notifyAfterDeadline;
}
public Boolean isNotifyModeNonstop() {
return notifyModeNonstop;
}
public void setNotifyModeNonstop(boolean notifyModeNonstop) {
this.notifyModeNonstop = notifyModeNonstop;
}
public Boolean isNotifyModeFive() {
return notifyModeFive;
}
public void setNotifyModeFive(boolean notifyModeFive) {
this.notifyModeFive = notifyModeFive;
}
public Date getRepeatUntil() {
return repeatUntil;
}
public void setRepeatUntil(Date repeatUntil) {
this.repeatUntil = repeatUntil;
}
public String getRecurrence() {
return recurrence;
}
public void setRecurrence(String recurrence) {
this.recurrence = recurrence;
}
}

@ -31,6 +31,7 @@ import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecovera
import com.google.api.services.tasks.model.TaskList;
import com.google.api.services.tasks.model.TaskLists;
import com.google.api.services.tasks.model.Tasks;
import com.google.gson.JsonSyntaxException;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Join;
@ -54,7 +55,6 @@ import com.todoroo.astrid.gtasks.api.GtasksInvoker;
import com.todoroo.astrid.gtasks.api.HttpNotFoundException;
import com.todoroo.astrid.gtasks.sync.GtasksSyncService;
import com.todoroo.astrid.gtasks.sync.GtasksTaskContainer;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.tags.TaskToTagMetadata;
import com.todoroo.astrid.utility.Constants;
@ -70,12 +70,14 @@ import org.tasks.time.DateTime;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import javax.inject.Inject;
@ -95,17 +97,11 @@ import static org.tasks.date.DateTimeUtils.newDateTime;
public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter {
private static final String DEFAULT_LIST = "@default"; //$NON-NLS-1$
private static final String NOTE_METADATA_PREFIX = "tasks";
private static final String NOTE_METADATA_KEY_TAGS = "tags";
private static final String NOTE_METADATA_KEY_IMPORTANCE = "prio";
private static final String NOTE_METADATA_KEY_HIDE = "hide";
private static final String NOTE_METADATA_KEY_REMINDER = "remind";
private static final String NOTE_METADATA_KEY_RECURRENCE = "recur";
private static final Pattern PATTERN_NOTES_METADATA = Pattern.compile("(.*)\\{" + NOTE_METADATA_PREFIX + "\\-([a-zA-Z0-9\\-\\_]+):([^}]+)\\}\\s*", Pattern.DOTALL);
private static final String NOTE_METADATA_KEYWORD = "tasks:additionalMetadata";
private static final Pattern PATTERN_NOTES_METADATA = Pattern.compile("(.*)\\{" + NOTE_METADATA_KEYWORD + "(\\{.*\\})\\}\\s*", Pattern.DOTALL);
public static final String LINE_FEED = "\n";
private static final int NOTE_MAX_LENGTH = 8100; // seams to be 8192
private Gson gsonBulider = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss").create();
@Inject GtasksPreferenceService gtasksPreferenceService;
@Inject Broadcaster broadcaster;
@ -337,31 +333,42 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
void writeNotesIfNecessary(Task task, com.google.api.services.tasks.model.Task remoteModel) {
ContentValues values = task.getChangedValues();
List<String> additionalMetaData = new ArrayList<>();
String additionalMetadata = null;
if (gtasksPreferenceService.getUseNoteForMetadataSync()) {
String tags = createTagList(task);
if (tags!=null) {
additionalMetaData.add(createNoteMetadata(NOTE_METADATA_KEY_TAGS, tags));
GoogleTaskAdditionalMetadata additionalMetadataObject = new GoogleTaskAdditionalMetadata();
List<String> tags = createTagList(task);
if (tags.size() > 0) {
additionalMetadataObject.setTags(tags);
}
int defaultImportance = preferences.getIntegerFromString(R.string.p_default_importance_key, Task.IMPORTANCE_SHOULD_DO);
if (task.getImportance()!=defaultImportance) {
additionalMetaData.add(createNoteMetadata(NOTE_METADATA_KEY_IMPORTANCE, GtasksApiUtilities.importanceToGtasksString(task.getImportance())));
if (task.getImportance() != defaultImportance) {
additionalMetadataObject.setImportance(GoogleTaskAdditionalMetadata.Importance.valueOf(task.getImportance()));
}
if (values.containsKey(Task.HIDE_UNTIL.name)) {
additionalMetaData.add(createNoteMetadata(NOTE_METADATA_KEY_HIDE, GtasksApiUtilities.unixTimeToGtasksStringTime(task.getHideUntil())));
additionalMetadataObject.setHideUntil(GtasksApiUtilities.unixTimeToDateTime(task.getHideUntil()));
}
int defaultReminderFlags = preferences.getIntegerFromString(R.string.p_default_reminders_key, Task.NOTIFY_AT_DEADLINE | Task.NOTIFY_AFTER_DEADLINE);
if ((defaultReminderFlags & Task.NOTIFY_AT_DEADLINE) != (task.getReminderFlags() & Task.NOTIFY_AT_DEADLINE)) {
additionalMetadataObject.setNotifyAtDeadline(task.isNotifyAtDeadline());
}
if ((defaultReminderFlags & Task.NOTIFY_AFTER_DEADLINE) != (task.getReminderFlags() & Task.NOTIFY_AFTER_DEADLINE)) {
additionalMetadataObject.setNotifyAfterDeadline(task.isNotifyAfterDeadline());
}
if (values.containsKey(Task.REMINDER_FLAGS.name)) {
additionalMetaData.add(createNoteMetadata(NOTE_METADATA_KEY_REMINDER, GtasksApiUtilities.reminderFlagsToGtasksString(task.isNotifyAtDeadline(), task.isNotifyAfterDeadline(), task.isNotifyModeNonstop(), task.isNotifyModeFive())));
if (task.isNotifyModeNonstop()) {
additionalMetadataObject.setNotifyModeNonstop(task.isNotifyModeNonstop());
}
if (task.isNotifyModeFive()) {
additionalMetadataObject.setNotifyModeFive(task.isNotifyModeFive());
}
if (values.containsKey(Task.RECURRENCE.name)) {
String repeatUntil = "";
additionalMetadataObject.setRecurrence(task.getRecurrence());
if (values.containsKey(Task.REPEAT_UNTIL.name)) {
repeatUntil = GtasksApiUtilities.NOTE_METADATA_VALUE_SPLIT_CHAR + GtasksApiUtilities.unixTimeToGtasksStringTime(task.getRepeatUntil());
additionalMetadataObject.setRepeatUntil(GtasksApiUtilities.unixTimeToDateTime(task.getRepeatUntil()));
}
additionalMetaData.add(createNoteMetadata(NOTE_METADATA_KEY_RECURRENCE, task.getRecurrence() + repeatUntil));
}
additionalMetadata = gsonBulider.toJson(additionalMetadataObject);
}
if (additionalMetaData.size()==0) {
if (additionalMetadata==null || additionalMetadata.trim().length()<=2) {
if (task.getMergedValues().containsKey(Task.NOTES.name)) {
remoteModel.setNotes(task.getNotes());
}
@ -370,22 +377,21 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
if (task.getMergedValues().containsKey(Task.NOTES.name)) {
notes.append(task.getNotes());
}
if (additionalMetaData.size() > 0 && notes.length() + LINE_FEED.length() < NOTE_MAX_LENGTH) {
if (notes.length() + additionalMetadata.length() < NOTE_MAX_LENGTH) {
notes.append(LINE_FEED);
for (String add : additionalMetaData) {
if (add != null && (notes.length() + add.length() + LINE_FEED.length()) < NOTE_MAX_LENGTH) {
notes.append(LINE_FEED);
notes.append(add);
}
}
notes.append(LINE_FEED);
notes.append("{");
notes.append(NOTE_METADATA_KEYWORD);
notes.append(additionalMetadata);
notes.append("}");
}
remoteModel.setNotes(notes.toString());
}
}
private String createTagList(Task task) {
private List<String> createTagList(Task task) {
List<Metadata> metadatas = metadataDao.byTaskAndKey(task.getId(), TaskToTagMetadata.KEY);
Set<String> tags = new HashSet<>();
Set<String> tags = new TreeSet<>();
for(Metadata metadata: metadatas) {
if (metadata!=null) {
String uuid = metadata.getValue(Metadata.VALUE2);
@ -393,73 +399,89 @@ public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter
TagData tagData = tagDataDao.getByUuid(uuid, TagData.ID);
if (tagData!=null) {
String tagName = tagData.getName();
// Skip empty tags or tags containig { } ;
if (tagName!=null && tagName.trim().length()>0 && tagName.indexOf('{')<0 && tagName.indexOf('}')<0 && tagName.indexOf(';')<0) {
// Skip empty tags or tags containig { } , ; [ ] # ' \
if (tagName!=null && tagName.trim().length()>0 && tagName.indexOf('{')<0 && tagName.indexOf('}')<0 && tagName.indexOf('[')<0 && tagName.indexOf(']')<0 && tagName.indexOf(',')<0 && tagName.indexOf(';')<0 && tagName.indexOf('"')<0 && tagName.indexOf('\'')<0 && tagName.indexOf('\\')<0) {
tags.add(tagName.trim());
}
}
}
}
}
return GtasksApiUtilities.tagsToGtaskTags(tags);
}
private String createNoteMetadata(String key, String value) {
if (value!=null) {
return "{" + NOTE_METADATA_PREFIX + "-" + key + ":" + value + "}";
} else {
return null;
}
return new ArrayList<>(tags);
}
void processNotes(Task task) {
String notes = task.getNotes();
Matcher m = PATTERN_NOTES_METADATA.matcher(notes);
while(m.matches()) {
if(m.matches()) {
notes = m.group(1).trim();
String metadataKey = m.group(2);
String metadataValue = m.group(3);
m = PATTERN_NOTES_METADATA.matcher(notes);
switch(metadataKey) {
case NOTE_METADATA_KEY_TAGS:
Set<String> tags = GtasksApiUtilities.gtasksTagsToTags(metadataValue);
String gson = m.group(2);
try {
GoogleTaskAdditionalMetadata additionalMetadataObject = gsonBulider.fromJson(gson, GoogleTaskAdditionalMetadata.class);
List<String> tags = additionalMetadataObject.getTags();
if (tags!=null && tags.size() > 0) {
for(String tag: tags) {
createLink(task, tag);
}
break;
case NOTE_METADATA_KEY_HIDE:
task.setHideUntil(GtasksApiUtilities.gtasksStringTimeToUnixTime(metadataValue));
break;
case NOTE_METADATA_KEY_IMPORTANCE:
int defaultImportance = preferences.getIntegerFromString(R.string.p_default_importance_key, Task.IMPORTANCE_SHOULD_DO);
task.setImportance(GtasksApiUtilities.gtasksStringToImportance(metadataValue, defaultImportance));
break;
case NOTE_METADATA_KEY_RECURRENCE:
String[] rec = metadataValue.split("" + GtasksApiUtilities.NOTE_METADATA_VALUE_SPLIT_CHAR);
if (rec!=null && rec.length>0) {
if (rec.length>1) {
long repeatUntil = GtasksApiUtilities.gtasksStringTimeToUnixTime(rec[rec.length-1]);
if (repeatUntil>0) {
task.setRepeatUntil(repeatUntil);
task.setRecurrence(metadataValue.substring(0, metadataValue.lastIndexOf(GtasksApiUtilities.NOTE_METADATA_VALUE_SPLIT_CHAR)));
} else {
task.setRecurrence(metadataValue);
}
} else {
task.setRecurrence(metadataValue);
}
}
if (additionalMetadataObject.getHideUntil()!=null) {
task.setHideUntil(GtasksApiUtilities.dateTimeToUnixTime(additionalMetadataObject.getHideUntil()));
}
if (additionalMetadataObject.getRecurrence()!=null) {
task.setRecurrence(additionalMetadataObject.getRecurrence());
}
if (additionalMetadataObject.getRepeatUntil()!=null) {
task.setRepeatUntil(GtasksApiUtilities.dateTimeToUnixTime(additionalMetadataObject.getRepeatUntil()));
}
int defaultImportance = preferences.getIntegerFromString(R.string.p_default_importance_key, Task.IMPORTANCE_SHOULD_DO);
if (additionalMetadataObject.getImportance()!=null && additionalMetadataObject.getImportance().getTaskImportance()!=defaultImportance) {
task.setImportance(additionalMetadataObject.getImportance().getTaskImportance());
}
int defaultReminderFlags = preferences.getIntegerFromString(R.string.p_default_reminders_key, Task.NOTIFY_AT_DEADLINE | Task.NOTIFY_AFTER_DEADLINE);
int reminderFlags = defaultReminderFlags;
boolean setRemindeFlags = false;
if (isSetAndNotDefault(additionalMetadataObject.isNotifyAtDeadline(), Task.NOTIFY_AT_DEADLINE, defaultReminderFlags)) {
setRemindeFlags = true;
if(additionalMetadataObject.isNotifyAtDeadline()) {
reminderFlags |= Task.NOTIFY_AT_DEADLINE;
} else {
reminderFlags &= ~Task.NOTIFY_AT_DEADLINE;
}
}
if (isSetAndNotDefault(additionalMetadataObject.isNotifyAfterDeadline(), Task.NOTIFY_AFTER_DEADLINE, defaultReminderFlags)) {
setRemindeFlags = true;
if(additionalMetadataObject.isNotifyAfterDeadline()) {
reminderFlags |= Task.NOTIFY_AFTER_DEADLINE;
} else {
reminderFlags &= ~Task.NOTIFY_AFTER_DEADLINE;
}
break;
case NOTE_METADATA_KEY_REMINDER:
task.setReminderFlags(GtasksApiUtilities.gtasksReminderFlagsTimeToFlags(metadataValue));
break;
default:
// Ignore
}
if (additionalMetadataObject.isNotifyModeFive()!=null) {
setRemindeFlags = true;
reminderFlags |= Task.NOTIFY_MODE_FIVE;
}
if (additionalMetadataObject.isNotifyModeNonstop()!=null) {
setRemindeFlags = true;
reminderFlags |= Task.NOTIFY_MODE_NONSTOP;
}
if (setRemindeFlags) {
task.setReminderFlags(reminderFlags);
}
} catch (JsonSyntaxException ex) {
// Ignore corrupt JSON
}
}
task.setNotes(notes);
}
private boolean isSetAndNotDefault(Boolean reminderFlag, int reminderFlagConstant, int defaultReminderFlags) {
return reminderFlag!=null &&
(
(reminderFlag && (defaultReminderFlags & reminderFlagConstant)==0) ||
(!reminderFlag && (defaultReminderFlags & reminderFlagConstant)!=0)
);
}
private void createLink(Task task, String tagName) {
TagData tagData = tagDataDao.getTagByName(tagName, TagData.NAME, TagData.UUID);
if (tagData == null) {

Loading…
Cancel
Save