Added default values for all things in creating a new list and syncing it. Also handling sync errors silently

pull/14/head
Tim Su 16 years ago
parent 8600a6a237
commit 9cdba9c17a

@ -44,16 +44,32 @@ public abstract class SynchronizationProvider<TYPE extends TaskContainer> {
/** /**
* Perform authenticate and other pre-synchronization steps, then * Perform authenticate and other pre-synchronization steps, then
* synchronize. * synchronize.
* @param context either the parent activity, or a background service *
* @param context
* either the parent activity, or a background service
*/ */
abstract protected void initiate(Context context); abstract protected void initiate(Context context);
/** /**
* Gets title of the notification bar notification
*
* @param context * @param context
* @return title of notification * @return title of notification
*/ */
abstract protected String getNotificationTitle(Context context); abstract protected String getNotificationTitle(Context context);
/**
* Deal with an exception that occurs during synchronization
*
* @param tag
* short string description of where error occurred
* @param e
* exception
* @param displayError
* whether to display error to the user
*/
abstract protected void handleException(String tag, Exception e, boolean displayError);
/** /**
* Create a task on the remote server. * Create a task on the remote server.
* *
@ -207,52 +223,60 @@ public abstract class SynchronizationProvider<TYPE extends TaskContainer> {
length = data.localCreated.getCount(); length = data.localCreated.getCount();
for(int i = 0; i < length; i++) { for(int i = 0; i < length; i++) {
data.localCreated.moveToNext(); data.localCreated.moveToNext();
TYPE local = read(data.localCreated); try {
TYPE local = read(data.localCreated);
String taskTitle = local.task.getValue(Task.TITLE);
String taskTitle = local.task.getValue(Task.TITLE);
/* If there exists an incoming remote task with the same name and no
* mapping, we don't want to create this on the remote server, /* If there exists an incoming remote task with the same name and no
* because user could have synchronized like this before. Instead, * mapping, we don't want to create this on the remote server,
* we create a mapping and do an update. * because user could have synchronized like this before. Instead,
*/ * we create a mapping and do an update.
if (remoteNewTaskNameMap.containsKey(taskTitle)) { */
int remoteIndex = remoteNewTaskNameMap.remove(taskTitle); if (remoteNewTaskNameMap.containsKey(taskTitle)) {
TYPE remote = data.remoteUpdated.get(remoteIndex); int remoteIndex = remoteNewTaskNameMap.remove(taskTitle);
TYPE remote = data.remoteUpdated.get(remoteIndex);
transferIdentifiers(remote, local);
push(local, remote); transferIdentifiers(remote, local);
push(local, remote);
// re-read remote task after merge, update remote task list
remote = pull(remote); // re-read remote task after merge, update remote task list
remote.task.setId(local.task.getId()); remote = pull(remote);
data.remoteUpdated.set(remoteIndex, remote); remote.task.setId(local.task.getId());
} else { data.remoteUpdated.set(remoteIndex, remote);
create(local); } else {
create(local);
}
write(local);
} catch (Exception e) {
handleException("sync-local-created", e, false); //$NON-NLS-1$
} }
write(local);
} }
// 2. UPDATE: for each updated local task // 2. UPDATE: for each updated local task
length = data.localUpdated.getCount(); length = data.localUpdated.getCount();
for(int i = 0; i < length; i++) { for(int i = 0; i < length; i++) {
data.localUpdated.moveToNext(); data.localUpdated.moveToNext();
TYPE local = read(data.localUpdated); try {
if(local.task == null) TYPE local = read(data.localUpdated);
continue; if(local.task == null)
continue;
// if there is a conflict, merge
int remoteIndex = matchTask((ArrayList<TYPE>)data.remoteUpdated, local); // if there is a conflict, merge
if(remoteIndex != -1) { int remoteIndex = matchTask((ArrayList<TYPE>)data.remoteUpdated, local);
TYPE remote = data.remoteUpdated.get(remoteIndex); if(remoteIndex != -1) {
push(local, remote); TYPE remote = data.remoteUpdated.get(remoteIndex);
push(local, remote);
// re-read remote task after merge
remote = pull(remote); // re-read remote task after merge
remote.task.setId(local.task.getId()); remote = pull(remote);
data.remoteUpdated.set(remoteIndex, remote); remote.task.setId(local.task.getId());
} else { data.remoteUpdated.set(remoteIndex, remote);
push(local, null); } else {
push(local, null);
}
} catch (Exception e) {
handleException("sync-local-updated", e, false); //$NON-NLS-1$
} }
} }
@ -290,7 +314,11 @@ public abstract class SynchronizationProvider<TYPE extends TaskContainer> {
length = data.remoteUpdated.size(); length = data.remoteUpdated.size();
for(int i = 0; i < length; i++) { for(int i = 0; i < length; i++) {
TYPE remote = data.remoteUpdated.get(i); TYPE remote = data.remoteUpdated.get(i);
write(remote); try {
write(remote);
} catch (Exception e) {
handleException("sync-remote-updated", e, false); //$NON-NLS-1$
}
} }
} }

@ -219,6 +219,19 @@ public abstract class AbstractModel implements Parcelable {
return false; return false;
} }
/**
* @param property
* @return true if setValues or values contains this property, and the value
* stored is not null
*/
public boolean containsNonNullValue(Property<?> property) {
if(setValues != null && setValues.containsKey(property.name))
return setValues.get(property.name) != null;
if(values != null && values.containsKey(property.name))
return values.get(property.name) != null;
return false;
}
// --- data storage // --- data storage
/** /**

@ -39,6 +39,9 @@ public class MilkFilterExposer extends BroadcastReceiver {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(Metadata.KEY.name, MilkTask.METADATA_KEY); values.put(Metadata.KEY.name, MilkTask.METADATA_KEY);
values.put(MilkTask.LIST_ID.name, list.id); values.put(MilkTask.LIST_ID.name, list.id);
values.put(MilkTask.TASK_SERIES_ID.name, 0);
values.put(MilkTask.TASK_ID.name, 0);
values.put(MilkTask.REPEATING.name, 0);
Filter filter = new Filter(listTitle, title, new QueryTemplate().join( Filter filter = new Filter(listTitle, title, new QueryTemplate().join(
MilkDataService.METADATA_JOIN).where(Criterion.and( MilkDataService.METADATA_JOIN).where(Criterion.and(
MetadataCriteria.withKey(MilkTask.METADATA_KEY), MetadataCriteria.withKey(MilkTask.METADATA_KEY),

@ -22,6 +22,7 @@ import com.timsu.astrid.R;
import com.todoroo.andlib.data.Property; import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.ExceptionService; import com.todoroo.andlib.service.ExceptionService;
import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.AndroidUtilities;
@ -100,12 +101,11 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
* error tag * error tag
* @param e * @param e
* exception * exception
* @param showErrorIfNeeded * @param showError
* whether to display a dialog * whether to display a dialog
*/ */
private void handleRtmException(Context context, String tag, Exception e, @Override
boolean showErrorIfNeeded) { protected void handleException(String tag, Exception e, boolean showError) {
Utilities.setLastError(e.toString()); Utilities.setLastError(e.toString());
// occurs when application was closed // occurs when application was closed
@ -118,7 +118,8 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
IOException) { IOException) {
Exception enclosedException = ((ServiceInternalException)e).getEnclosedException(); Exception enclosedException = ((ServiceInternalException)e).getEnclosedException();
exceptionService.reportError(tag + "-ioexception", enclosedException); //$NON-NLS-1$ exceptionService.reportError(tag + "-ioexception", enclosedException); //$NON-NLS-1$
if(showErrorIfNeeded) { if(showError) {
Context context = ContextManager.getContext();
showError(context, enclosedException, showError(context, enclosedException,
context.getString(R.string.rmilk_ioerror)); context.getString(R.string.rmilk_ioerror));
} }
@ -126,8 +127,10 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
if(e instanceof ServiceInternalException) if(e instanceof ServiceInternalException)
e = ((ServiceInternalException)e).getEnclosedException(); e = ((ServiceInternalException)e).getEnclosedException();
exceptionService.reportError(tag + "-unhandled", e); //$NON-NLS-1$ exceptionService.reportError(tag + "-unhandled", e); //$NON-NLS-1$
if(showErrorIfNeeded) if(showError) {
Context context = ContextManager.getContext();
showError(context, e, null); showError(context, e, null);
}
} }
} }
@ -169,7 +172,7 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
try { try {
String token = rtmService.completeAuthorization(); String token = rtmService.completeAuthorization();
Utilities.setToken(token); Utilities.setToken(token);
performSync(context); performSync();
return; return;
} catch (Exception e) { } catch (Exception e) {
@ -211,12 +214,12 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
context.startActivity(intent); context.startActivity(intent);
} else { } else {
performSync(context); performSync();
} }
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
// occurs when application was closed // occurs when application was closed
} catch (Exception e) { } catch (Exception e) {
handleRtmException(context, "rtm-authenticate", e, true); handleException("rtm-authenticate", e, true);
} finally { } finally {
Utilities.stopOngoing(); Utilities.stopOngoing();
} }
@ -226,7 +229,7 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
// ----------------------------------------------------- synchronization! // ----------------------------------------------------- synchronization!
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
protected void performSync(final Context context) { protected void performSync() {
try { try {
// get RTM timeline // get RTM timeline
timeline = rtmService.timelines_create(); timeline = rtmService.timelines_create();
@ -249,7 +252,7 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
RtmTasks tasks = rtmService.tasks_getList(null, filter, lastSyncDate); RtmTasks tasks = rtmService.tasks_getList(null, filter, lastSyncDate);
addTasksToList(tasks, remoteChanges); addTasksToList(tasks, remoteChanges);
} catch (Exception e) { } catch (Exception e) {
handleRtmException(context, "rtm-quick-sync", e, false); //$NON-NLS-1$ handleException("rtm-quick-sync", e, false); //$NON-NLS-1$
remoteChanges.clear(); remoteChanges.clear();
shouldSyncIndividualLists = true; shouldSyncIndividualLists = true;
} }
@ -264,7 +267,7 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
filter, lastSyncDate); filter, lastSyncDate);
addTasksToList(tasks, remoteChanges); addTasksToList(tasks, remoteChanges);
} catch (Exception e) { } catch (Exception e) {
handleRtmException(context, "rtm-indiv-sync", e, true); //$NON-NLS-1$ handleException("rtm-indiv-sync", e, true); //$NON-NLS-1$
continue; continue;
} }
} }
@ -284,7 +287,7 @@ public class RTMSyncProvider extends SynchronizationProvider<RTMTaskContainer> {
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
// occurs when application was closed // occurs when application was closed
} catch (Exception e) { } catch (Exception e) {
handleRtmException(context, "rtm-sync", e, true); //$NON-NLS-1$ handleException("rtm-sync", e, true); //$NON-NLS-1$
} }
} }

@ -44,13 +44,13 @@ public class RTMTaskContainer extends TaskContainer {
for(Iterator<Metadata> iterator = metadata.iterator(); iterator.hasNext(); ) { for(Iterator<Metadata> iterator = metadata.iterator(); iterator.hasNext(); ) {
Metadata item = iterator.next(); Metadata item = iterator.next();
if(MilkTask.METADATA_KEY.equals(item.getValue(Metadata.KEY))) { if(MilkTask.METADATA_KEY.equals(item.getValue(Metadata.KEY))) {
if(item.containsValue(MilkTask.LIST_ID)) if(item.containsNonNullValue(MilkTask.LIST_ID))
listId = item.getValue(MilkTask.LIST_ID); listId = item.getValue(MilkTask.LIST_ID);
if(item.containsValue(MilkTask.TASK_SERIES_ID)) if(item.containsNonNullValue(MilkTask.TASK_SERIES_ID))
taskSeriesId = item.getValue(MilkTask.TASK_SERIES_ID); taskSeriesId = item.getValue(MilkTask.TASK_SERIES_ID);
if(item.containsValue(MilkTask.TASK_ID)) if(item.containsNonNullValue(MilkTask.TASK_ID))
taskId = item.getValue(MilkTask.TASK_ID); taskId = item.getValue(MilkTask.TASK_ID);
if(item.containsValue(MilkTask.REPEATING)) if(item.containsNonNullValue(MilkTask.REPEATING))
repeating = item.getValue(MilkTask.REPEATING) == 1; repeating = item.getValue(MilkTask.REPEATING) == 1;
iterator.remove(); iterator.remove();
break; break;

Loading…
Cancel
Save