@ -7,13 +7,16 @@ import java.util.LinkedList;
import java.util.List ;
import java.util.List ;
import android.app.Activity ;
import android.app.Activity ;
import android.app.Dialog ;
import android.app.ProgressDialog ;
import android.app.ProgressDialog ;
import android.content.Context ;
import android.content.Context ;
import android.content.DialogInterface ;
import android.content.res.Resources ;
import android.content.res.Resources ;
import android.os.Handler ;
import android.os.Handler ;
import android.util.Log ;
import android.util.Log ;
import com.timsu.astrid.R ;
import com.timsu.astrid.R ;
import com.timsu.astrid.data.alerts.AlertController ;
import com.timsu.astrid.data.sync.SyncDataController ;
import com.timsu.astrid.data.sync.SyncDataController ;
import com.timsu.astrid.data.sync.SyncMapping ;
import com.timsu.astrid.data.sync.SyncMapping ;
import com.timsu.astrid.data.tag.TagController ;
import com.timsu.astrid.data.tag.TagController ;
@ -23,6 +26,8 @@ import com.timsu.astrid.data.task.TaskController;
import com.timsu.astrid.data.task.TaskIdentifier ;
import com.timsu.astrid.data.task.TaskIdentifier ;
import com.timsu.astrid.data.task.TaskModelForSync ;
import com.timsu.astrid.data.task.TaskModelForSync ;
import com.timsu.astrid.utilities.DialogUtilities ;
import com.timsu.astrid.utilities.DialogUtilities ;
import com.timsu.astrid.utilities.Notifications ;
import com.timsu.astrid.utilities.Preferences ;
/ * * A service that synchronizes with Astrid
/ * * A service that synchronizes with Astrid
*
*
@ -32,35 +37,26 @@ import com.timsu.astrid.utilities.DialogUtilities;
public abstract class SynchronizationService {
public abstract class SynchronizationService {
private int id ;
private int id ;
protected ProgressDialog progressDialog ;
static ProgressDialog progressDialog ;
protected Handler syncHandler = new Handler ( ) ;
protected Handler syncHandler ;
public SynchronizationService ( int id ) {
public SynchronizationService ( int id ) {
this . id = id ;
this . id = id ;
}
}
// called off the UI thread. does some setup
// called off the UI thread. does some setup
void synchronizeService ( final Activity activity ) {
void synchronizeService ( final Activity activity ) {
syncHandler . post ( new Runnable ( ) {
syncHandler = new Handler ( ) ;
@Override
progressDialog = new ProgressDialog ( activity ) ;
public void run ( ) {
progressDialog . setIcon ( android . R . drawable . ic_dialog_alert ) ;
progressDialog = new ProgressDialog ( activity ) ;
progressDialog . setTitle ( "Synchronization" ) ;
progressDialog . setIcon ( android . R . drawable . ic_dialog_alert ) ;
progressDialog . setProgressStyle ( ProgressDialog . STYLE_HORIZONTAL ) ;
progressDialog . setTitle ( "Synchronization" ) ;
progressDialog . setMax ( 100 ) ;
progressDialog . setProgressStyle ( ProgressDialog . STYLE_HORIZONTAL ) ;
progressDialog . setMessage ( "Checking Authorization..." ) ;
progressDialog . setMax ( 100 ) ;
progressDialog . setProgress ( 0 ) ;
progressDialog . setMessage ( "Checking Authorization..." ) ;
progressDialog . setCancelable ( false ) ;
progressDialog . setProgress ( 0 ) ;
progressDialog . show ( ) ;
progressDialog . show ( ) ;
}
} ) ;
synchronize ( activity ) ;
synchronize ( activity ) ;
syncHandler . post ( new Runnable ( ) {
@Override
public void run ( ) {
progressDialog . dismiss ( ) ;
}
} ) ;
}
}
/** Synchronize with the service */
/** Synchronize with the service */
@ -142,14 +138,27 @@ public abstract class SynchronizationService {
protected void synchronizeTasks ( final Activity activity , List < TaskProxy > remoteTasks ,
protected void synchronizeTasks ( final Activity activity , List < TaskProxy > remoteTasks ,
SynchronizeHelper helper ) throws IOException {
SynchronizeHelper helper ) throws IOException {
final SyncStats stats = new SyncStats ( ) ;
final SyncStats stats = new SyncStats ( ) ;
final StringBuilder log = new StringBuilder ( ) ;
syncHandler . post ( new Runnable ( ) {
@Override
public void run ( ) {
if ( ! progressDialog . isShowing ( ) )
progressDialog . show ( ) ;
}
} ) ;
SyncDataController syncController = Synchronizer . getSyncController ( activity ) ;
SyncDataController syncController = Synchronizer . getSyncController ( activity ) ;
TaskController taskController = Synchronizer . getTaskController ( activity ) ;
TaskController taskController = Synchronizer . getTaskController ( activity ) ;
TagController tagController = Synchronizer . getTagController ( activity ) ;
TagController tagController = Synchronizer . getTagController ( activity ) ;
AlertController alertController = Synchronizer . getAlertController ( activity ) ;
// get data out of the database (note we get non-completed tasks only)
// get data out of the database
HashSet < SyncMapping > mappings = syncController . getSyncMapping ( getId ( ) ) ;
HashSet < SyncMapping > mappings = syncController . getSyncMapping ( getId ( ) ) ;
HashSet < TaskIdentifier > localTasks = taskController . getActiveTaskIdentifiers ( ) ;
HashSet < TaskIdentifier > activeTasks = taskController .
getActiveTaskIdentifiers ( ) ;
HashSet < TaskIdentifier > allTasks = taskController .
getAllTaskIdentifiers ( ) ;
HashMap < TagIdentifier , TagModelForView > tags =
HashMap < TagIdentifier , TagModelForView > tags =
tagController . getAllTagsAsMap ( activity ) ;
tagController . getAllTagsAsMap ( activity ) ;
@ -179,6 +188,7 @@ public abstract class SynchronizationService {
}
}
// grab tasks without a sync mapping and create them remotely
// grab tasks without a sync mapping and create them remotely
log . append ( ">> on remote server:\n" ) ;
syncHandler . post ( new Runnable ( ) {
syncHandler . post ( new Runnable ( ) {
@Override
@Override
public void run ( ) {
public void run ( ) {
@ -186,8 +196,7 @@ public abstract class SynchronizationService {
progressDialog . setProgress ( 0 ) ;
progressDialog . setProgress ( 0 ) ;
}
}
} ) ;
} ) ;
HashSet < TaskIdentifier > newlyCreatedTasks = new HashSet < TaskIdentifier > (
HashSet < TaskIdentifier > newlyCreatedTasks = new HashSet < TaskIdentifier > ( activeTasks ) ;
localTasks ) ;
newlyCreatedTasks . removeAll ( mappedTasks ) ;
newlyCreatedTasks . removeAll ( mappedTasks ) ;
for ( TaskIdentifier taskId : newlyCreatedTasks ) {
for ( TaskIdentifier taskId : newlyCreatedTasks ) {
LinkedList < TagIdentifier > taskTags =
LinkedList < TagIdentifier > taskTags =
@ -210,6 +219,7 @@ public abstract class SynchronizationService {
helper . pushTask ( localTask , mapping ) ;
helper . pushTask ( localTask , mapping ) ;
// update stats
// update stats
log . append ( "add " + task . getName ( ) + "\n" ) ;
stats . remoteCreatedTasks + + ;
stats . remoteCreatedTasks + + ;
syncHandler . post ( new ProgressUpdater ( stats . remoteCreatedTasks ,
syncHandler . post ( new ProgressUpdater ( stats . remoteCreatedTasks ,
newlyCreatedTasks . size ( ) ) ) ;
newlyCreatedTasks . size ( ) ) ) ;
@ -223,8 +233,9 @@ public abstract class SynchronizationService {
progressDialog . setProgress ( 0 ) ;
progressDialog . setProgress ( 0 ) ;
}
}
} ) ;
} ) ;
HashSet < TaskIdentifier > deletedTasks = new HashSet < TaskIdentifier > ( mappedTasks ) ;
HashSet < TaskIdentifier > deletedTasks = new HashSet < TaskIdentifier > (
deletedTasks . removeAll ( localTasks ) ;
mappedTasks ) ;
deletedTasks . removeAll ( allTasks ) ;
for ( TaskIdentifier taskId : deletedTasks ) {
for ( TaskIdentifier taskId : deletedTasks ) {
SyncMapping mapping = localIdToSyncMapping . get ( taskId ) ;
SyncMapping mapping = localIdToSyncMapping . get ( taskId ) ;
syncController . deleteSyncMapping ( mapping ) ;
syncController . deleteSyncMapping ( mapping ) ;
@ -236,6 +247,7 @@ public abstract class SynchronizationService {
remoteChangeMap . remove ( taskId ) ;
remoteChangeMap . remove ( taskId ) ;
// update stats
// update stats
log . append ( "del #" + taskId . getId ( ) + "\n" ) ;
stats . remoteDeletedTasks + + ;
stats . remoteDeletedTasks + + ;
syncHandler . post ( new ProgressUpdater ( stats . remoteDeletedTasks ,
syncHandler . post ( new ProgressUpdater ( stats . remoteDeletedTasks ,
deletedTasks . size ( ) ) ) ;
deletedTasks . size ( ) ) ) ;
@ -262,6 +274,9 @@ public abstract class SynchronizationService {
remoteConflict = remoteChangeMap . get ( mapping . getTask ( ) ) ;
remoteConflict = remoteChangeMap . get ( mapping . getTask ( ) ) ;
localTask . mergeWithOther ( remoteConflict ) ;
localTask . mergeWithOther ( remoteConflict ) ;
stats . mergedTasks + + ;
stats . mergedTasks + + ;
log . append ( "mrg " + task . getName ( ) + "\n" ) ;
} else {
log . append ( "upd " + task . getName ( ) + "\n" ) ;
}
}
try {
try {
@ -276,13 +291,21 @@ public abstract class SynchronizationService {
TaskProxy newTask = helper . refetchTask ( remoteConflict ) ;
TaskProxy newTask = helper . refetchTask ( remoteConflict ) ;
remoteTasks . remove ( remoteConflict ) ;
remoteTasks . remove ( remoteConflict ) ;
remoteTasks . add ( newTask ) ;
remoteTasks . add ( newTask ) ;
}
} else
stats . remoteUpdatedTasks + + ;
stats . remoteUpdatedTasks + + ;
syncHandler . post ( new ProgressUpdater ( stats . remoteUpdatedTasks ,
syncHandler . post ( new ProgressUpdater ( stats . remoteUpdatedTasks ,
localChanges . size ( ) ) ) ;
localChanges . size ( ) ) ) ;
}
}
// load remote information
// load remote information
log . append ( ">> on astrid:\n" ) ;
syncHandler . post ( new Runnable ( ) {
@Override
public void run ( ) {
progressDialog . setMessage ( "Updating local tasks" ) ;
progressDialog . setProgress ( 0 ) ;
}
} ) ;
for ( TaskProxy remoteTask : remoteTasks ) {
for ( TaskProxy remoteTask : remoteTasks ) {
SyncMapping mapping = null ;
SyncMapping mapping = null ;
TaskModelForSync task = null ;
TaskModelForSync task = null ;
@ -297,18 +320,23 @@ public abstract class SynchronizationService {
task = taskController . searchForTaskForSync ( remoteTask . name ) ;
task = taskController . searchForTaskForSync ( remoteTask . name ) ;
if ( task = = null ) {
if ( task = = null ) {
task = new TaskModelForSync ( ) ;
task = new TaskModelForSync ( ) ;
setupTaskDefaults ( activity , task ) ;
log . append ( "add " + remoteTask . name + "\n" ) ;
} else {
} else {
mapping = localIdToSyncMapping . get ( task . getTaskIdentifier ( ) ) ;
mapping = localIdToSyncMapping . get ( task . getTaskIdentifier ( ) ) ;
log . append ( "mov " + remoteTask . name + "\n" ) ;
}
}
} else {
} else {
mapping = remoteIdToSyncMapping . get ( remoteTask . getRemoteId ( ) ) ;
mapping = remoteIdToSyncMapping . get ( remoteTask . getRemoteId ( ) ) ;
if ( remoteTask . isDeleted ( ) ) {
if ( remoteTask . isDeleted ( ) ) {
taskController . deleteTask ( mapping . getTask ( ) ) ;
taskController . deleteTask ( mapping . getTask ( ) ) ;
syncController . deleteSyncMapping ( mapping ) ;
syncController . deleteSyncMapping ( mapping ) ;
log . append ( "del " + remoteTask . name + "\n" ) ;
stats . localDeletedTasks + + ;
stats . localDeletedTasks + + ;
continue ;
continue ;
}
}
log . append ( "upd " + remoteTask . name + "\n" ) ;
task = taskController . fetchTaskForSync (
task = taskController . fetchTaskForSync (
mapping . getTask ( ) ) ;
mapping . getTask ( ) ) ;
}
}
@ -346,6 +374,9 @@ public abstract class SynchronizationService {
syncController . saveSyncMapping ( mapping ) ;
syncController . saveSyncMapping ( mapping ) ;
stats . localCreatedTasks + + ;
stats . localCreatedTasks + + ;
}
}
Notifications . updateAlarm ( activity , taskController , alertController ,
task ) ;
}
}
stats . localUpdatedTasks - = stats . localCreatedTasks ;
stats . localUpdatedTasks - = stats . localCreatedTasks ;
@ -353,11 +384,18 @@ public abstract class SynchronizationService {
syncHandler . post ( new Runnable ( ) {
syncHandler . post ( new Runnable ( ) {
@Override
@Override
public void run ( ) {
public void run ( ) {
stats . showDialog ( activity );
stats . showDialog ( activity , log . toString ( ) );
}
}
} ) ;
} ) ;
}
}
/** Set up defaults from preferences for this task */
private void setupTaskDefaults ( Activity activity , TaskModelForSync task ) {
Integer reminder = Preferences . getDefaultReminder ( activity ) ;
if ( reminder ! = null )
task . setNotificationIntervalSeconds ( 24 * 3600 * reminder ) ;
}
// --- helper classes
// --- helper classes
protected class SyncStats {
protected class SyncStats {
@ -372,17 +410,29 @@ public abstract class SynchronizationService {
int remoteDeletedTasks = 0 ;
int remoteDeletedTasks = 0 ;
/** Display a dialog with statistics */
/** Display a dialog with statistics */
public void showDialog ( Context context ) {
public void showDialog ( final Activity activity , String log ) {
progressDialog . dismiss ( ) ;
progressDialog . hide ( ) ;
Dialog . OnClickListener finishListener = new Dialog . OnClickListener ( ) {
@Override
public void onClick ( DialogInterface dialog ,
int which ) {
Synchronizer . continueSynchronization ( activity ) ;
}
} ;
if ( equals ( new SyncStats ( ) ) ) { // i.e. no change
// nothing updated
DialogUtilities . okDialog ( context , "Nothing to do!" , null ) ;
if ( localCreatedTasks + localUpdatedTasks + localDeletedTasks +
mergedTasks + remoteCreatedTasks + remoteDeletedTasks +
remoteUpdatedTasks = = 0 ) {
DialogUtilities . okDialog ( activity , "Sync: Up to date!" , finishListener ) ;
return ;
return ;
}
}
StringBuilder sb = new StringBuilder ( ) ;
StringBuilder sb = new StringBuilder ( ) ;
sb . append ( getName ( ) ) . append ( " Sync Results:" ) ; // TODO i18n
sb . append ( getName ( ) ) . append ( " Sync Results:" ) ; // TODO i18n
sb . append ( "\n\n--- Astrid Tasks ---" ) ;
sb . append ( "\n\n" ) ;
sb . append ( log ) ;
sb . append ( "\n--- Summary: Astrid Tasks ---" ) ;
if ( localCreatedTasks > 0 )
if ( localCreatedTasks > 0 )
sb . append ( "\nCreated: " + localCreatedTasks ) ;
sb . append ( "\nCreated: " + localCreatedTasks ) ;
if ( localUpdatedTasks > 0 )
if ( localUpdatedTasks > 0 )
@ -393,7 +443,7 @@ public abstract class SynchronizationService {
if ( mergedTasks > 0 )
if ( mergedTasks > 0 )
sb . append ( "\n\nMerged: " + localCreatedTasks ) ;
sb . append ( "\n\nMerged: " + localCreatedTasks ) ;
sb . append ( "\n\n--- Remote Tasks ---") ;
sb . append ( "\n\n--- Summary: Remote Server ---") ;
if ( remoteCreatedTasks > 0 )
if ( remoteCreatedTasks > 0 )
sb . append ( "\nCreated: " + remoteCreatedTasks ) ;
sb . append ( "\nCreated: " + remoteCreatedTasks ) ;
if ( remoteUpdatedTasks > 0 )
if ( remoteUpdatedTasks > 0 )
@ -403,7 +453,7 @@ public abstract class SynchronizationService {
sb . append ( "\n" ) ;
sb . append ( "\n" ) ;
DialogUtilities . okDialog ( context, sb . toString ( ) , null ) ;
DialogUtilities . okDialog ( activity, sb . toString ( ) , finishListener ) ;
}
}
}
}