~tomdroid-maintainers/tomdroid/note-editing-and-syncing

« back to all changes in this revision

Viewing changes to src/org/tomdroid/sync/SyncService.java

  • Committer: noahy
  • Date: 2012-08-09 05:55:10 UTC
  • Revision ID: noahy57@gmail.com-20120809055510-54yzsm6f8aq24avw
radically simplified sync, progress on progress bar...

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
package org.tomdroid.sync;
26
26
 
27
27
import android.app.Activity;
 
28
import android.content.ContentResolver;
 
29
import android.content.Intent;
28
30
import android.database.Cursor;
29
31
import android.net.Uri;
 
32
import android.os.Bundle;
30
33
import android.os.Handler;
31
34
import android.os.Message;
 
35
import android.text.format.Time;
32
36
import android.widget.Toast;
 
37
 
 
38
import org.json.JSONException;
 
39
import org.json.JSONObject;
33
40
import org.tomdroid.Note;
34
41
import org.tomdroid.NoteManager;
35
42
import org.tomdroid.R;
 
43
import org.tomdroid.ui.SyncDialog;
36
44
import org.tomdroid.ui.Tomdroid;
37
45
import org.tomdroid.util.ErrorList;
 
46
import org.tomdroid.util.Preferences;
38
47
import org.tomdroid.util.TLog;
39
48
 
40
49
import java.util.ArrayList;
59
68
         */
60
69
        private ErrorList syncErrors;
61
70
        private int syncProgress = 100;
62
 
        
 
71
 
63
72
        // handler messages
64
73
        public final static int PARSING_COMPLETE = 1;
65
74
        public final static int PARSING_FAILED = 2;
74
83
        public final static int NOTE_DELETE_ERROR = 11;
75
84
        public final static int NOTE_PULL_ERROR = 12;
76
85
        public final static int BEGIN_PROGRESS = 13;
77
 
                
 
86
        public final static int INCREMENT_PROGRESS = 14;
 
87
        public final static int IN_PROGRESS = 15;
78
88
        public SyncService(Activity activity, Handler handler) {
79
89
                
80
90
                this.activity = activity;
86
96
        public void startSynchronization(boolean push) {
87
97
                
88
98
                if (syncProgress != 100){
89
 
                        Toast.makeText(activity, activity.getString(R.string.messageSyncAlreadyInProgress), Toast.LENGTH_SHORT).show();
 
99
                        sendMessage(IN_PROGRESS);
90
100
                        return;
91
101
                }
92
102
                
144
154
        }
145
155
        
146
156
        /**
147
 
         * Insert notes in the content provider. 
148
 
         * 
149
 
         * @param notes The notes to insert.
150
 
         */
151
 
        
152
 
        protected void insertNotes(List<Note> notes, boolean push) {
153
 
                if(notes.size() > 0)
154
 
                        NoteManager.putNotes(this.activity, notes, push);
155
 
        }
156
 
        /**
157
 
         * Insert last note in the content provider. tell the 
 
157
         * Insert last note in the content provider.
158
158
         * 
159
159
         * @param note The note to insert.
160
160
         */
161
161
        
162
 
        protected void insertNote(Note note, boolean push) {
163
 
                NoteManager.putNote(this.activity, note, push);
 
162
        protected void insertNote(Note note) {
 
163
                NoteManager.putNote(this.activity, note);
 
164
                sendMessage(INCREMENT_PROGRESS );
164
165
        }       
165
 
        /**
166
 
         * Delete notes in the content provider. The guids passed identify the notes existing
167
 
         * on the remote end (ie. that shouldn't be deleted).
168
 
         * 
169
 
         * @param remoteGuids The notes NOT to delete.
170
 
         */
171
 
        
172
 
        protected void deleteNotes(ArrayList<String> remoteGuids) {
173
 
                
174
 
                Cursor localGuids = NoteManager.getGuids(this.activity);
175
 
                
176
 
                // cursor must not be null and must return more than 0 entry 
177
 
                if (!(localGuids == null || localGuids.getCount() == 0)) {
178
 
                        
179
 
                        String localGuid;
180
 
                        
181
 
                        localGuids.moveToFirst();
182
 
                        
183
 
                        do {
184
 
                                localGuid = localGuids.getString(localGuids.getColumnIndexOrThrow(Note.GUID));
185
 
                                
186
 
                                if(!remoteGuids.contains(localGuid)) {
187
 
                                        int id = localGuids.getInt(localGuids.getColumnIndexOrThrow(Note.ID));
188
 
                                        NoteManager.deleteNote(this.activity, id);
189
 
                                }
190
 
                                
191
 
                        } while (localGuids.moveToNext());
192
 
                        
193
 
                } else {
194
 
                        
195
 
                        // TODO send an error to the user
196
 
                        TLog.d(TAG, "Cursor returned null or 0 notes");
197
 
                }
198
 
        }
199
 
 
200
 
        /**
201
 
         * Add notes from the content provider. The guids passed identify the notes existing
202
 
         * on the remote end (ie. that shouldn't be added).
203
 
         * 
204
 
         * @param remoteGuids The notes NOT to add.
205
 
         */
206
 
        
207
 
        protected List<Note> pullNotes(ArrayList<String> remoteGuids) {
208
 
                
209
 
                Cursor localGuids = NoteManager.getGuids(this.activity);
210
 
                String lastGUID = null;
211
 
                // cursor must not be null and must return more than 0 entry 
212
 
                List<Note> notes = new ArrayList<Note>();
213
 
                if (!(localGuids == null || localGuids.getCount() == 0)) {
214
 
                        
215
 
                        String localGuid;
216
 
                        
217
 
                        localGuids.moveToFirst();
218
 
                        do {
219
 
                                localGuid = localGuids.getString(localGuids.getColumnIndexOrThrow(Note.GUID));
220
 
                                
221
 
                                if(!remoteGuids.contains(localGuid)) {
222
 
                                        int id = localGuids.getInt(localGuids.getColumnIndexOrThrow(Note.ID));
223
 
                                        notes.add(NoteManager.getNote(this.activity, Uri.parse(Tomdroid.CONTENT_URI + "/" + id)));
224
 
                                        lastGUID = localGuid;
225
 
                                }
226
 
                                
227
 
                        } while (localGuids.moveToNext());
228
 
                        
229
 
 
230
 
                } else {
231
 
                        // TODO send an error to the user
232
 
                        TLog.d(TAG, "Cursor returned null or 0 notes");
233
 
                }
234
 
                return notes;
235
 
        }
236
 
        
 
166
 
 
167
 
 
168
        protected void syncNotes(ArrayList<Note> notesList, boolean push) {
 
169
 
 
170
                ArrayList<String> remoteGuids = new ArrayList<String>();
 
171
                ArrayList<Note> pushableNotes = new ArrayList<Note>();
 
172
                ArrayList<Note> pullableNotes = new ArrayList<Note>();
 
173
                HashMap<String,Note[]> comparableNotes = new HashMap<String,Note[]>();
 
174
                ArrayList<String> deleteableNotes = new ArrayList<String>();
 
175
                
 
176
                for ( Note remoteNote : notesList) {
 
177
                        Note localNote = NoteManager.getNoteByGuid(activity,remoteNote.getGuid());
 
178
                        remoteGuids.add(remoteNote.getGuid());
 
179
                        if(localNote == null) {
 
180
                                pullableNotes.add(remoteNote);
 
181
                        }
 
182
                        else if(push) {
 
183
                                Note[] compNotes = {localNote, remoteNote};
 
184
                                comparableNotes.put(localNote.getGuid(), compNotes);
 
185
                        }
 
186
                }
 
187
                // get non-remote notes
 
188
                
 
189
                Cursor localGuids = NoteManager.getGuids(this.activity);
 
190
                // cursor must not be null and must return more than 0 entry 
 
191
                if (!(localGuids == null || localGuids.getCount() == 0)) {
 
192
                        
 
193
                        String localGuid;
 
194
                        
 
195
                        localGuids.moveToFirst();
 
196
                        do {
 
197
                                localGuid = localGuids.getString(localGuids.getColumnIndexOrThrow(Note.GUID));
 
198
                                
 
199
                                if(!remoteGuids.contains(localGuid)) {
 
200
                                        int id = localGuids.getInt(localGuids.getColumnIndexOrThrow(Note.ID));
 
201
                                        Note note = NoteManager.getNoteByGuid(this.activity, localGuid);
 
202
                                        if(note.getTags().contains("system:deleted"))
 
203
                                                deleteableNotes.add(note.getGuid());
 
204
                                        else
 
205
                                                pushableNotes.add(note);
 
206
                                }
 
207
                                
 
208
                        } while (localGuids.moveToNext());
 
209
 
 
210
                }
 
211
                TLog.d(TAG, "Notes to pull: {0}, Notes to push: {1}, Notes to delete: {2}, Notes to compare: {3}",pullableNotes.size(),pushableNotes.size(),deleteableNotes.size(),comparableNotes.size());
 
212
                
 
213
        // init progress bar
 
214
 
 
215
                HashMap<String, Object> hm = new HashMap<String, Object>();
 
216
                hm.put("total", pullableNotes.size()+pushableNotes.size()+comparableNotes.size()+deleteableNotes.size());
 
217
                sendMessage(BEGIN_PROGRESS,hm);
 
218
 
 
219
        // deal with notes that are not in local content provider - always pull
 
220
                
 
221
                for(Note note : pullableNotes)
 
222
                        insertNote(note);
 
223
 
 
224
                setSyncProgress(70);
 
225
                
 
226
        // deal with notes not in remote service - push or delete
 
227
                        
 
228
                // if two-way sync, push local only notes, otherwise delete them
 
229
                
 
230
                if(push) {
 
231
                        SyncManager.getInstance().getCurrentService().pushNotes(pushableNotes);
 
232
                }
 
233
                else
 
234
                        deleteNonRemoteNotes(pullableNotes);
 
235
 
 
236
                // deleted notes not in remote
 
237
                
 
238
                SyncManager.getInstance().getCurrentService().deleteNotes(deleteableNotes);
 
239
                
 
240
                
 
241
                setSyncProgress(80);
 
242
 
 
243
        // deal with notes in both - compare and push, pull or diff
 
244
                
 
245
                compareNotes(comparableNotes,push);
 
246
                
 
247
                setSyncProgress(90);
 
248
        }
 
249
 
 
250
        protected void deleteNonRemoteNotes(ArrayList<Note> notes) {
 
251
                
 
252
                for(Note note : notes) {
 
253
                        NoteManager.deleteNote(this.activity, note.getDbId());
 
254
                        sendMessage(INCREMENT_PROGRESS);
 
255
                }
 
256
        }
 
257
 
 
258
        
 
259
        private void compareNotes(HashMap<String, Note[]> comparableNotes, boolean push) {
 
260
 
 
261
                String syncDateString = Preferences.getString(Preferences.Key.LATEST_SYNC_DATE);
 
262
                Time syncDate = new Time();
 
263
                syncDate.parse3339(syncDateString);
 
264
 
 
265
                int compareCount = 0;
 
266
                
 
267
                for(Note[] notes : comparableNotes.values()) {
 
268
                        
 
269
                        Note localNote = notes[0];
 
270
                        Note remoteNote = notes[1];
 
271
 
 
272
                        int compareSyncLocal = Time.compare(syncDate, localNote.getLastChangeDate());
 
273
                        int compareSyncRemote = Time.compare(syncDate, remoteNote.getLastChangeDate());
 
274
                        int compareBoth = Time.compare(localNote.getLastChangeDate(), remoteNote.getLastChangeDate());
 
275
 
 
276
                // if not two-way, overwrite the local version
 
277
                
 
278
                        if(!push) {
 
279
                                NoteManager.putNote(activity, remoteNote);
 
280
                        }
 
281
                        else {
 
282
                                
 
283
                                // check date difference
 
284
                                
 
285
                                TLog.v(TAG, "compare both: {0}, compare local: {1}, compare remote: {2}", compareBoth, compareSyncLocal, compareSyncRemote);
 
286
                                if(compareBoth != 0)
 
287
                                        TLog.v(TAG, "Different note dates");
 
288
                                if((compareSyncLocal < 0 && compareSyncRemote < 0) || (compareSyncLocal > 0 && compareSyncRemote > 0))
 
289
                                        TLog.v(TAG, "both either older or newer");
 
290
                                        
 
291
                                if(compareBoth != 0 && ((compareSyncLocal < 0 && compareSyncRemote < 0) || (compareSyncLocal > 0 && compareSyncRemote > 0))) { // sync conflict!  both are older or newer than last sync
 
292
                                        
 
293
                                        TLog.v(TAG, "note conflict... showing resolution dialog TITLE:{0} GUID:{1}", localNote.getTitle(), localNote.getGuid());
 
294
                                        
 
295
                                        // send everything to Tomdroid so it can show Sync Dialog
 
296
                                    Bundle bundle = new Bundle();       
 
297
                                        bundle.putString("title",remoteNote.getTitle());
 
298
                                        bundle.putString("file",remoteNote.getFileName());
 
299
                                        bundle.putString("guid",remoteNote.getGuid());
 
300
                                        bundle.putString("date",remoteNote.getLastChangeDate().format3339(false));
 
301
                                        bundle.putString("content", remoteNote.getXmlContent());
 
302
                                        bundle.putString("tags", remoteNote.getTags());
 
303
                                        bundle.putInt("datediff", compareBoth);
 
304
        
 
305
                                        Intent intent = new Intent(activity.getApplicationContext(), SyncDialog.class); 
 
306
                                        intent.putExtras(bundle);
 
307
 
 
308
                                        activity.startActivityForResult(intent, compareCount++);                
 
309
                                }
 
310
                                else if(compareBoth > 0) { // local newer 
 
311
 
 
312
                                        TLog.v(TAG, "local newer, pushing local to remote");
 
313
        
 
314
                                                /* pushing local changes, reject older incoming note.
 
315
                                                 * If the local counterpart has the tag "system:deleted", delete from both local and remote.
 
316
                                                 * Otherwise, push local to remote.
 
317
                                                 */
 
318
                                                
 
319
                                                if(localNote.getTags().contains("system:deleted")) {
 
320
                                                        TLog.v(TAG, "local note is deleted, deleting from server TITLE:{0} GUID:{1}", localNote.getTitle(),localNote.getGuid());
 
321
                                                        SyncManager.getInstance().deleteNote(localNote.getGuid()); // delete from remote
 
322
                                                        NoteManager.deleteNote(activity,localNote.getDbId()); // really delete locally
 
323
                                                }
 
324
                                                else {
 
325
                                                        TLog.v(TAG, "local note is newer, sending new version TITLE:{0} GUID:{1}", localNote.getTitle(),localNote.getGuid());
 
326
                                                        SyncManager.getInstance().pushNote(localNote);
 
327
                                                }
 
328
                                }
 
329
                                else if(compareBoth < 0) { // local older
 
330
                                        TLog.v(TAG, "Local note is older, updating in content provider TITLE:{0} GUID:{1}", localNote.getTitle(), localNote.getGuid());
 
331
                                        sendMessage(INCREMENT_PROGRESS);
 
332
                                        // pull remote changes
 
333
                                        NoteManager.putNote(activity, remoteNote);
 
334
                                }
 
335
                                else { // both same date
 
336
                                        if(localNote.getTags().contains("system:deleted")) {
 
337
                                                TLog.v(TAG, "local note is deleted, deleting from server TITLE:{0} GUID:{1}", localNote.getTitle(),localNote.getGuid());
 
338
                                                SyncManager.getInstance().deleteNote(localNote.getGuid()); // delete from remote
 
339
                                                NoteManager.deleteNote(activity,localNote.getDbId()); // really delete locally
 
340
                                        }
 
341
                                        else {
 
342
                                                TLog.v(TAG, "Notes are same date, updating in content provider TITLE:{0} GUID:{1}", localNote.getTitle(), localNote.getGuid());
 
343
                                                
 
344
                                                sendMessage(INCREMENT_PROGRESS);
 
345
                                                // pull remote changes anyway
 
346
                                                NoteManager.putNote(activity, remoteNote);
 
347
                                        }
 
348
                                }
 
349
                        }
 
350
                }
 
351
        }
 
352
 
237
353
        /**
238
354
         * Send a message to the main UI.
239
355
         * 
277
393
         * @param progress 
278
394
         */
279
395
        
280
 
        protected void setSyncProgress(int progress) {
 
396
        public void setSyncProgress(int progress) {
281
397
                synchronized (TAG) {
282
398
                        TLog.v(TAG, "sync progress: {0}", progress);
283
399
                        Message progressMessage = new Message();
315
431
                // TODO Auto-generated method stub
316
432
                
317
433
        }
 
434
 
 
435
        protected void pushNotes(ArrayList<Note> notes) {
 
436
                if(notes.size() == 0)
 
437
                        return;
 
438
                
 
439
                TLog.v(TAG, "pushing {0} notes to remote service",notes.size());
 
440
                for(Note note : notes) {
 
441
                        pushNote(note);
 
442
                }
 
443
        }
 
444
        protected void deleteNotes(ArrayList<String> notes) {
 
445
                if(notes.size() == 0)
 
446
                        return;
 
447
                
 
448
                TLog.v(TAG, "deleting {0} notes from remote service",notes.size());
 
449
                for(String note : notes) {
 
450
                        deleteNote(note);
 
451
                }
 
452
        }
 
453
 
 
454
 
318
455
}
 
 
b'\\ No newline at end of file'