|
1 /** |
|
2 * Copyright (c) 2012-2013, Gerald Garcia, David Wiesner, Timo Berger |
|
3 * |
|
4 * This file is part of Andoid Caldav Sync Adapter Free. |
|
5 * |
|
6 * Andoid Caldav Sync Adapter Free is free software: you can redistribute |
|
7 * it and/or modify it under the terms of the GNU General Public License |
|
8 * as published by the Free Software Foundation, either version 3 of the |
|
9 * License, or at your option any later version. |
|
10 * |
|
11 * Andoid Caldav Sync Adapter Free is distributed in the hope that |
|
12 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied |
|
13 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 * GNU General Public License for more details. |
|
15 * |
|
16 * You should have received a copy of the GNU General Public License |
|
17 * along with Andoid Caldav Sync Adapter Free. |
|
18 * If not, see <http://www.gnu.org/licenses/>. |
|
19 * |
|
20 */ |
|
21 |
|
22 package org.gege.caldavsyncadapter.syncadapter; |
|
23 |
|
24 import java.io.IOException; |
|
25 import java.net.URI; |
|
26 //import java.net.MalformedURLException; |
|
27 import java.net.URISyntaxException; |
|
28 import java.util.ArrayList; |
|
29 //import java.security.GeneralSecurityException; |
|
30 |
|
31 import javax.xml.parsers.ParserConfigurationException; |
|
32 |
|
33 import net.fortuna.ical4j.data.ParserException; |
|
34 |
|
35 import org.apache.http.ParseException; |
|
36 import org.apache.http.client.ClientProtocolException; |
|
37 import org.gege.caldavsyncadapter.Event; |
|
38 import org.gege.caldavsyncadapter.android.entities.AndroidEvent; |
|
39 import org.gege.caldavsyncadapter.authenticator.AuthenticatorActivity; |
|
40 import org.gege.caldavsyncadapter.caldav.CaldavFacade; |
|
41 import org.gege.caldavsyncadapter.caldav.CaldavProtocolException; |
|
42 import org.gege.caldavsyncadapter.caldav.entities.DavCalendar; |
|
43 import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent; |
|
44 import org.gege.caldavsyncadapter.caldav.entities.CalendarList; |
|
45 import org.gege.caldavsyncadapter.caldav.entities.DavCalendar.CalendarSource; |
|
46 import org.gege.caldavsyncadapter.syncadapter.notifications.NotificationsHelper; |
|
47 import org.xml.sax.SAXException; |
|
48 |
|
49 import android.accounts.Account; |
|
50 import android.accounts.AccountManager; |
|
51 import android.content.AbstractThreadedSyncAdapter; |
|
52 import android.content.ContentProviderClient; |
|
53 import android.content.ContentUris; |
|
54 import android.content.ContentValues; |
|
55 import android.content.Context; |
|
56 import android.content.SyncResult; |
|
57 import android.content.SyncStats; |
|
58 import android.content.pm.PackageManager.NameNotFoundException; |
|
59 import android.database.Cursor; |
|
60 import android.net.Uri; |
|
61 import android.os.Bundle; |
|
62 import android.os.RemoteException; |
|
63 import android.provider.CalendarContract.Attendees; |
|
64 import android.provider.CalendarContract.Calendars; |
|
65 import android.provider.CalendarContract.Events; |
|
66 import android.provider.CalendarContract.Reminders; |
|
67 import android.util.Log; |
|
68 |
|
69 public class SyncAdapter extends AbstractThreadedSyncAdapter { |
|
70 |
|
71 private static final String TAG = "SyncAdapter"; |
|
72 private AccountManager mAccountManager; |
|
73 private String mVersion = ""; |
|
74 private int mCountPerformSync = 0; |
|
75 private int mCountSyncCanceled = 0; |
|
76 private int mCountProviderFailed = 0; |
|
77 |
|
78 private int mCountProviderFailedMax = 3; |
|
79 // private Context mContext; |
|
80 |
|
81 |
|
82 /* private static final String[] CALENDAR_PROJECTION = new String[] { |
|
83 Calendars._ID, // 0 |
|
84 Calendars.ACCOUNT_NAME, // 1 |
|
85 Calendars.CALENDAR_DISPLAY_NAME, // 2 |
|
86 Calendars.OWNER_ACCOUNT, // 3 |
|
87 Calendar.CTAG // 4 |
|
88 };*/ |
|
89 |
|
90 /* // The indices for the projection array above. |
|
91 private static final int PROJECTION_ID_INDEX = 0; |
|
92 private static final int PROJECTION_ACCOUNT_NAME_INDEX = 1; |
|
93 private static final int PROJECTION_DISPLAY_NAME_INDEX = 2; |
|
94 private static final int PROJECTION_OWNER_ACCOUNT_INDEX = 3; |
|
95 */ |
|
96 |
|
97 /* |
|
98 private static final String[] EVENT_PROJECTION = new String[] { |
|
99 Events._ID, |
|
100 Events._SYNC_ID, |
|
101 Events.SYNC_DATA1, |
|
102 Events.CALENDAR_ID |
|
103 }; |
|
104 */ |
|
105 |
|
106 // ignore same CTag |
|
107 //private static final boolean FORCE_SYNCHRONIZE = false; |
|
108 // drop all calendar before synchro |
|
109 //private static final boolean DROP_CALENDAR_EVENTS = false; |
|
110 |
|
111 public SyncAdapter(Context context, boolean autoInitialize) { |
|
112 super(context, autoInitialize); |
|
113 //android.os.Debug.waitForDebugger(); |
|
114 mAccountManager = AccountManager.get(context); |
|
115 try { |
|
116 mVersion = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName; |
|
117 } catch (NameNotFoundException e) { |
|
118 e.printStackTrace(); |
|
119 } |
|
120 // mContext = context; |
|
121 } |
|
122 |
|
123 @Override |
|
124 public void onPerformSync(Account account, Bundle extras, String authority, |
|
125 ContentProviderClient provider, SyncResult syncResult) { |
|
126 boolean bolError = false; |
|
127 |
|
128 String url = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_URL_KEY); |
|
129 this.mCountPerformSync += 1; |
|
130 Log.v(TAG, "onPerformSync() count:" + String.valueOf(this.mCountPerformSync) + " on " + account.name + " with URL " + url); |
|
131 |
|
132 CalendarList serverCalList; |
|
133 |
|
134 CalendarList androidCalList = new CalendarList(account, provider, CalendarSource.Android, url); |
|
135 androidCalList.readCalendarFromClient(); |
|
136 ArrayList<Uri> notifyList = new ArrayList<Uri>(); |
|
137 |
|
138 try { |
|
139 String Username = ""; |
|
140 String UserDataVersion = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_VERSION); |
|
141 if (UserDataVersion == null) { |
|
142 Username = account.name; |
|
143 } else { |
|
144 Username = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_USERNAME); |
|
145 } |
|
146 |
|
147 CaldavFacade facade = new CaldavFacade(Username, mAccountManager.getPassword(account), url); |
|
148 facade.setAccount(account); |
|
149 facade.setProvider(provider); |
|
150 facade.setVersion(mVersion); |
|
151 serverCalList = facade.getCalendarList(this.getContext()); |
|
152 //String davProperties = facade.getLastDav(); |
|
153 Log.i(TAG, String.valueOf(androidCalList.getCalendarList().size()) + " calendars found at android"); |
|
154 |
|
155 for (DavCalendar serverCalendar : serverCalList.getCalendarList()) { |
|
156 Log.i(TAG, "Detected calendar name=" + serverCalendar.getCalendarDisplayName() + " URI=" + serverCalendar.getURI()); |
|
157 |
|
158 Uri androidCalendarUri = serverCalendar.checkAndroidCalendarList(androidCalList, this.getContext()); |
|
159 |
|
160 // check if the adapter was able to get an existing calendar or create a new one |
|
161 if (androidCalendarUri != null) { |
|
162 // the provider seems to work correct, reset the counter |
|
163 mCountProviderFailed = 0; |
|
164 DavCalendar androidCalendar = androidCalList.getCalendarByAndroidUri(androidCalendarUri); |
|
165 |
|
166 //if ((FORCE_SYNCHRONIZE) || (androidCalendar.getcTag() == null) || (!androidCalendar.getcTag().equals(serverCalendar.getcTag()))) { |
|
167 if ((androidCalendar.getcTag() == null) || (!androidCalendar.getcTag().equals(serverCalendar.getcTag()))) { |
|
168 Log.d(TAG, "CTag has changed, something to synchronise"); |
|
169 if (serverCalendar.readCalendarEvents(facade)) { |
|
170 this.synchroniseEvents(androidCalendar, serverCalendar, syncResult.stats, notifyList); |
|
171 |
|
172 Log.d(TAG, "Updating stored CTag"); |
|
173 //serverCalendar.updateAndroidCalendar(androidCalendarUri, Calendar.CTAG, serverCalendar.getcTag()); |
|
174 androidCalendar.setCTag(serverCalendar.getcTag(), true); |
|
175 } else { |
|
176 Log.d(TAG, "unable to read events from server calendar"); |
|
177 } |
|
178 } else { |
|
179 Log.d(TAG, "CTag has not changed, nothing to do"); |
|
180 |
|
181 /* this is unnecessary. "SkippedEntries" are: |
|
182 * Counter for tracking how many entries, either from the server or the local store, |
|
183 * were ignored during the sync operation. This could happen if the SyncAdapter detected |
|
184 * some unparsable data but decided to skip it and move on rather than failing immediately. |
|
185 */ |
|
186 |
|
187 /*long CalendarID = ContentUris.parseId(androidCalendarUri); |
|
188 String selection = "(" + Events.CALENDAR_ID + " = ?)"; |
|
189 String[] selectionArgs = new String[] {String.valueOf(CalendarID)}; |
|
190 Cursor countCursor = provider.query(Events.CONTENT_URI, new String[] {"count(*) AS count"}, |
|
191 selection, |
|
192 selectionArgs, |
|
193 null); |
|
194 |
|
195 countCursor.moveToFirst(); |
|
196 int count = countCursor.getInt(0); |
|
197 syncResult.stats.numSkippedEntries += count; |
|
198 countCursor.close();*/ |
|
199 |
|
200 } |
|
201 |
|
202 this.checkDirtyAndroidEvents(provider, account, androidCalendarUri, facade, serverCalendar.getURI(), syncResult.stats, notifyList); |
|
203 } else { |
|
204 // this happens if the data provider failes to get an existing or create a new calendar |
|
205 mCountProviderFailed += 1; |
|
206 Log.e(TAG, "failed to get an existing or create a new calendar"); |
|
207 syncResult.stats.numIoExceptions += 1; |
|
208 if (mCountProviderFailed >= mCountProviderFailedMax) { |
|
209 // see issue #96 |
|
210 NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (provider failed)", "are you using CyanogenMod in Incognito Mode?"); |
|
211 } else { |
|
212 NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (provider failed)", "the provider failed to get an existing or create a new calendar"); |
|
213 } |
|
214 bolError = true; |
|
215 } |
|
216 } |
|
217 |
|
218 if (!bolError) { |
|
219 // check whether a calendar is not synced -> delete it at android |
|
220 androidCalList.deleteCalendarOnClientSideOnly(this.getContext()); |
|
221 } |
|
222 |
|
223 // notify the ContentResolver |
|
224 for (Uri uri : androidCalList.getNotifyList()) { |
|
225 this.getContext().getContentResolver().notifyChange(uri, null); |
|
226 } |
|
227 for (Uri uri : serverCalList.getNotifyList()) { |
|
228 this.getContext().getContentResolver().notifyChange(uri, null); |
|
229 } |
|
230 for (Uri uri : notifyList) { |
|
231 this.getContext().getContentResolver().notifyChange(uri, null); |
|
232 } |
|
233 |
|
234 //Log.i(TAG,"Statistiks for Calendar: " + serverCalendar.getURI().toString()); |
|
235 //Log.i(TAG,"Statistiks for AndroidCalendar: " + androidCalendar.getAndroidCalendarUri().toString()); |
|
236 Log.i(TAG,"Entries: " + String.valueOf(syncResult.stats.numEntries)); |
|
237 Log.i(TAG,"Rows inserted: " + String.valueOf(syncResult.stats.numInserts)); |
|
238 Log.i(TAG,"Rows updated: " + String.valueOf(syncResult.stats.numUpdates)); |
|
239 Log.i(TAG,"Rows deleted: " + String.valueOf(syncResult.stats.numDeletes)); |
|
240 Log.i(TAG,"Rows skipped: " + String.valueOf(syncResult.stats.numSkippedEntries)); |
|
241 Log.i(TAG,"Io Exceptions: " + String.valueOf(syncResult.stats.numIoExceptions)); |
|
242 Log.i(TAG,"Parse Exceptions: " + String.valueOf(syncResult.stats.numParseExceptions)); |
|
243 Log.i(TAG,"Auth Exceptions: " + String.valueOf(syncResult.stats.numAuthExceptions)); |
|
244 Log.i(TAG,"Conflict Detected Exceptions: " + String.valueOf(syncResult.stats.numConflictDetectedExceptions)); |
|
245 |
|
246 /*} catch (final AuthenticatorException e) { |
|
247 syncResult.stats.numParseExceptions++; |
|
248 Log.e(TAG, "AuthenticatorException", e);*/ |
|
249 /*} catch (final OperationCanceledException e) { |
|
250 Log.e(TAG, "OperationCanceledExcetpion", e);*/ |
|
251 } catch (final IOException e) { |
|
252 Log.e(TAG, "IOException", e); |
|
253 syncResult.stats.numIoExceptions++; |
|
254 NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (IO)", e.getMessage()); |
|
255 //NotificationsHelper.getCurrentSyncLog().addException(e); |
|
256 /*} catch (final AuthenticationException e) { |
|
257 //mAccountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE, authtoken); |
|
258 syncResult.stats.numAuthExceptions++; |
|
259 Log.e(TAG, "AuthenticationException", e);*/ |
|
260 } catch (final ParseException e) { |
|
261 syncResult.stats.numParseExceptions++; |
|
262 Log.e(TAG, "ParseException", e); |
|
263 NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (parsing)", e.getMessage()); |
|
264 //NotificationsHelper.getCurrentSyncLog().addException(e); |
|
265 /*} catch (final JSONException e) { |
|
266 syncResult.stats.numParseExceptions++; |
|
267 Log.e(TAG, "JSONException", e);*/ |
|
268 } catch (Exception e) { |
|
269 Log.e(TAG, "Updating calendar exception " + e.getClass().getName(), e); |
|
270 syncResult.stats.numParseExceptions++; |
|
271 NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (general)", e.getMessage()); |
|
272 //NotificationsHelper.getCurrentSyncLog().addException(e); |
|
273 //throw new RuntimeException(e); |
|
274 } |
|
275 } |
|
276 |
|
277 public void onSyncCanceled () { |
|
278 //TODO: implement SyncCanceled |
|
279 this.mCountSyncCanceled += 1; |
|
280 Log.v(TAG, "onSyncCanceled() count:" + String.valueOf(this.mCountSyncCanceled)); |
|
281 } |
|
282 |
|
283 |
|
284 /** |
|
285 * both calender event and android event have been found. |
|
286 * server wins always at the moment. |
|
287 * @param androidCalendar |
|
288 * @param serverCalendar |
|
289 * @param stats |
|
290 * @param notifyList |
|
291 * @throws ClientProtocolException |
|
292 * @throws URISyntaxException |
|
293 * @throws IOException |
|
294 * @throws ParserConfigurationException |
|
295 * @throws SAXException |
|
296 * @throws RemoteException |
|
297 * @throws CaldavProtocolException |
|
298 * @throws ParserException |
|
299 * @see SyncAdapter#updateAndroidEvent(ContentProviderClient, Account, AndroidEvent, CalendarEvent) |
|
300 * @see SyncAdapter#tagAndroidEvent(ContentProviderClient, Account, AndroidEvent) |
|
301 * @see SyncAdapter#untagAndroidEvents(ContentProviderClient, Account, Uri) |
|
302 * @see SyncAdapter#deleteUntaggedEvents(ContentProviderClient, Account, Uri) |
|
303 */ |
|
304 private void synchroniseEvents( |
|
305 DavCalendar androidCalendar, |
|
306 DavCalendar serverCalendar, |
|
307 SyncStats stats, |
|
308 ArrayList<Uri> notifyList |
|
309 ) throws ClientProtocolException, URISyntaxException, IOException, ParserConfigurationException, SAXException, RemoteException, CaldavProtocolException, ParserException { |
|
310 |
|
311 /*if (DROP_CALENDAR_EVENTS) { |
|
312 dropAllEvents(account, provider, androidCalendar.getAndroidCalendarUri()); |
|
313 }*/ |
|
314 |
|
315 int rowInsert = 0; |
|
316 int rowUpdate = 0; |
|
317 int rowTag = 0; |
|
318 int rowDelete = 0; |
|
319 int rowUntag = 0; |
|
320 int rowSkip = 0; |
|
321 |
|
322 for (CalendarEvent calendarEvent : serverCalendar.getCalendarEvents()) { |
|
323 try { |
|
324 AndroidEvent androidEvent = calendarEvent.getAndroidEvent(androidCalendar); |
|
325 |
|
326 Log.i(TAG, "Event " + calendarEvent.getUri().toString()+ " androidUri="+androidEvent); |
|
327 |
|
328 if (androidEvent == null) { |
|
329 /* new android event */ |
|
330 if (calendarEvent.createAndroidEvent(androidCalendar)) { |
|
331 rowInsert += 1; |
|
332 androidEvent = calendarEvent.getAndroidEvent(androidCalendar); |
|
333 notifyList.add(androidEvent.getUri()); |
|
334 } else { |
|
335 rowSkip += 1; |
|
336 } |
|
337 } else { |
|
338 /* the android exists */ |
|
339 String androidETag = androidEvent.getETag(); |
|
340 if (androidETag == null) |
|
341 androidETag = ""; |
|
342 Log.d(TAG, "Event compare: " + androidETag + " <> " + calendarEvent.getETag().toString()); |
|
343 if ((androidEvent.getETag() == null) || (!androidETag.equals(calendarEvent.getETag()))) { |
|
344 /* the android event is getting updated */ |
|
345 if (calendarEvent.updateAndroidEvent(androidEvent)) { |
|
346 rowUpdate += 1; |
|
347 notifyList.add(androidEvent.getUri()); |
|
348 } else { |
|
349 rowSkip += 1; |
|
350 } |
|
351 } |
|
352 } |
|
353 if (androidEvent != null) |
|
354 //if (androidEvent.tagAndroidEvent()) |
|
355 if (androidCalendar.tagAndroidEvent(androidEvent)) |
|
356 rowTag += 1; |
|
357 |
|
358 |
|
359 } catch (ParserException ex) { |
|
360 Log.e(TAG, "Parser exception", ex); |
|
361 stats.numParseExceptions++; |
|
362 |
|
363 NotificationsHelper.signalSyncErrors(getContext(), "Caldav sync error (parsing)", ex.getMessage()); |
|
364 //NotificationsHelper.getCurrentSyncLog().addException(ex); |
|
365 } catch (CaldavProtocolException ex) { |
|
366 Log.e(TAG, "Caldav exception", ex); |
|
367 stats.numParseExceptions++; |
|
368 |
|
369 NotificationsHelper.signalSyncErrors(getContext(), "Caldav sync error (caldav)", ex.getMessage()); |
|
370 //NotificationsHelper.getCurrentSyncLog().addException(ex); |
|
371 } |
|
372 } |
|
373 |
|
374 rowDelete = androidCalendar.deleteUntaggedEvents(); |
|
375 rowUntag = androidCalendar.untagAndroidEvents(); |
|
376 |
|
377 /*Log.i(TAG,"Statistiks for Calendar: " + serverCalendar.getURI().toString()); |
|
378 Log.i(TAG,"Statistiks for AndroidCalendar: " + androidCalendar.getAndroidCalendarUri().toString()); |
|
379 Log.i(TAG,"Rows inserted: " + String.valueOf(rowInsert)); |
|
380 Log.i(TAG,"Rows updated: " + String.valueOf(rowUpdate)); |
|
381 Log.i(TAG,"Rows deleted: " + String.valueOf(rowDelete)); |
|
382 Log.i(TAG,"Rows skipped: " + String.valueOf(rowSkip));*/ |
|
383 Log.i(TAG,"Rows tagged: " + String.valueOf(rowTag)); |
|
384 Log.i(TAG,"Rows untagged: " + String.valueOf(rowUntag)); |
|
385 |
|
386 stats.numInserts += rowInsert; |
|
387 stats.numUpdates += rowUpdate; |
|
388 stats.numDeletes += rowDelete; |
|
389 stats.numSkippedEntries += rowSkip; |
|
390 stats.numEntries += rowInsert + rowUpdate + rowDelete; |
|
391 |
|
392 } |
|
393 |
|
394 /** |
|
395 * checks the android events for the dirty flag. |
|
396 * the flag is set by android when the event has been changed. |
|
397 * the dirty flag is removed when an android event has been updated from calendar event |
|
398 * @param provider |
|
399 * @param account |
|
400 * @param calendarUri |
|
401 * @param facade |
|
402 * @param caldavCalendarUri |
|
403 * @param stats |
|
404 * @param notifyList |
|
405 * @return count of dirty events |
|
406 */ |
|
407 private int checkDirtyAndroidEvents( |
|
408 ContentProviderClient provider, |
|
409 Account account, |
|
410 Uri calendarUri, |
|
411 CaldavFacade facade, |
|
412 URI caldavCalendarUri, |
|
413 SyncStats stats, |
|
414 ArrayList<Uri> notifyList |
|
415 ) { |
|
416 Cursor curEvent = null; |
|
417 Cursor curAttendee = null; |
|
418 Cursor curReminder = null; |
|
419 Long EventID; |
|
420 Long CalendarID; |
|
421 AndroidEvent androidEvent = null; |
|
422 int rowDirty = 0; |
|
423 int rowInsert = 0; |
|
424 int rowUpdate = 0; |
|
425 int rowDelete = 0; |
|
426 |
|
427 try { |
|
428 CalendarID = ContentUris.parseId(calendarUri); |
|
429 String selection = "(" + Events.DIRTY + " = ?) AND (" + Events.CALENDAR_ID + " = ?)"; |
|
430 String[] selectionArgs = new String[] {"1", CalendarID.toString()}; |
|
431 curEvent = provider.query(Events.CONTENT_URI, null, selection, selectionArgs, null); |
|
432 |
|
433 while (curEvent.moveToNext()) { |
|
434 EventID = curEvent.getLong(curEvent.getColumnIndex(Events._ID)); |
|
435 Uri returnedUri = ContentUris.withAppendedId(Events.CONTENT_URI, EventID); |
|
436 |
|
437 //androidEvent = new AndroidEvent(account, provider, returnedUri, calendarUri); |
|
438 androidEvent = new AndroidEvent(returnedUri, calendarUri); |
|
439 androidEvent.readContentValues(curEvent); |
|
440 |
|
441 selection = "(" + Attendees.EVENT_ID + " = ?)"; |
|
442 selectionArgs = new String[] {String.valueOf(EventID)}; |
|
443 curAttendee = provider.query(Attendees.CONTENT_URI, null, selection, selectionArgs, null); |
|
444 selection = "(" + Reminders.EVENT_ID + " = ?)"; |
|
445 selectionArgs = new String[] {String.valueOf(EventID)}; |
|
446 curReminder = provider.query(Reminders.CONTENT_URI, null, selection, selectionArgs, null); |
|
447 androidEvent.readAttendees(curAttendee); |
|
448 androidEvent.readReminder(curReminder); |
|
449 curAttendee.close(); |
|
450 curReminder.close(); |
|
451 |
|
452 String SyncID = androidEvent.ContentValues.getAsString(Events._SYNC_ID); |
|
453 |
|
454 boolean Deleted = false; |
|
455 int intDeleted = 0; |
|
456 intDeleted = curEvent.getInt(curEvent.getColumnIndex(Events.DELETED)); |
|
457 Deleted = (intDeleted == 1); |
|
458 |
|
459 if (SyncID == null) { |
|
460 // new Android event |
|
461 String newGUID = java.util.UUID.randomUUID().toString() + "-caldavsyncadapter"; |
|
462 String calendarPath = caldavCalendarUri.getPath(); |
|
463 if (!calendarPath.endsWith("/")) |
|
464 calendarPath += "/"; |
|
465 |
|
466 SyncID = calendarPath + newGUID + ".ics"; |
|
467 |
|
468 androidEvent.createIcs(newGUID); |
|
469 |
|
470 if (facade.createEvent(URI.create(SyncID), androidEvent.getIcsEvent().toString())) { |
|
471 //HINT: bugfix for google calendar replace("@", "%40") |
|
472 if (SyncID.contains("@")) |
|
473 SyncID = SyncID.replace("@", "%40"); |
|
474 ContentValues values = new ContentValues(); |
|
475 values.put(Events._SYNC_ID, SyncID); |
|
476 |
|
477 //google doesn't send the etag after creation |
|
478 //HINT: my SabreDAV send always the same etag after putting a new event |
|
479 //String LastETag = facade.getLastETag(); |
|
480 //if (!LastETag.equals("")) { |
|
481 // values.put(Event.ETAG, LastETag); |
|
482 //} else { |
|
483 //so get the etag with a new REPORT |
|
484 CalendarEvent calendarEvent = new CalendarEvent(account, provider); |
|
485 calendarEvent.calendarURL = caldavCalendarUri.toURL(); |
|
486 URI SyncURI = new URI(SyncID); |
|
487 calendarEvent.setUri(SyncURI); |
|
488 CaldavFacade.getEvent(calendarEvent); |
|
489 values.put(Event.ETAG, calendarEvent.getETag()); |
|
490 //} |
|
491 values.put(Event.UID, newGUID); |
|
492 values.put(Events.DIRTY, 0); |
|
493 values.put(Event.RAWDATA, androidEvent.getIcsEvent().toString()); |
|
494 |
|
495 int rowCount = provider.update(asSyncAdapter(androidEvent.getUri(), account.name, account.type), values, null, null); |
|
496 if (rowCount == 1) { |
|
497 rowInsert += 1; |
|
498 notifyList.add(androidEvent.getUri()); |
|
499 } |
|
500 } |
|
501 } else if (Deleted) { |
|
502 // deleted Android event |
|
503 if (facade.deleteEvent(URI.create(SyncID), androidEvent.getETag())) { |
|
504 String mSelectionClause = "(" + Events._ID + "= ?)"; |
|
505 String[] mSelectionArgs = {String.valueOf(EventID)}; |
|
506 |
|
507 int countDeleted = provider.delete(asSyncAdapter(Events.CONTENT_URI, account.name, account.type), mSelectionClause, mSelectionArgs); |
|
508 |
|
509 if (countDeleted == 1) { |
|
510 rowDelete += 1; |
|
511 notifyList.add(androidEvent.getUri()); |
|
512 } |
|
513 } |
|
514 } else { |
|
515 //update the android event to the server |
|
516 String uid = androidEvent.getUID(); |
|
517 if ((uid == null) || (uid.equals(""))) { |
|
518 //COMPAT: this is needed because in the past, the UID was not stored in the android event |
|
519 CalendarEvent calendarEvent = new CalendarEvent(account, provider); |
|
520 URI syncURI = new URI(SyncID); |
|
521 calendarEvent.setUri(syncURI); |
|
522 calendarEvent.calendarURL = caldavCalendarUri.toURL(); |
|
523 if (calendarEvent.fetchBody()) { |
|
524 calendarEvent.readContentValues(); |
|
525 uid = calendarEvent.getUID(); |
|
526 } |
|
527 } |
|
528 if (uid != null) { |
|
529 androidEvent.createIcs(uid); |
|
530 |
|
531 if (facade.updateEvent(URI.create(SyncID), androidEvent.getIcsEvent().toString(), androidEvent.getETag())) { |
|
532 selection = "(" + Events._ID + "= ?)"; |
|
533 selectionArgs = new String[] {EventID.toString()}; |
|
534 androidEvent.ContentValues.put(Events.DIRTY, 0); |
|
535 |
|
536 //google doesn't send the etag after update |
|
537 String LastETag = facade.getLastETag(); |
|
538 if (!LastETag.equals("")) { |
|
539 androidEvent.ContentValues.put(Event.ETAG, LastETag); |
|
540 } else { |
|
541 //so get the etag with a new REPORT |
|
542 CalendarEvent calendarEvent = new CalendarEvent(account, provider); |
|
543 calendarEvent.calendarURL = caldavCalendarUri.toURL(); |
|
544 URI SyncURI = new URI(SyncID); |
|
545 calendarEvent.setUri(SyncURI); |
|
546 CaldavFacade.getEvent(calendarEvent); |
|
547 androidEvent.ContentValues.put(Event.ETAG, calendarEvent.getETag()); |
|
548 } |
|
549 androidEvent.ContentValues.put(Event.RAWDATA, androidEvent.getIcsEvent().toString()); |
|
550 int RowCount = provider.update(asSyncAdapter(androidEvent.getUri(), account.name, account.type), androidEvent.ContentValues, null, null); |
|
551 |
|
552 if (RowCount == 1) { |
|
553 rowUpdate += 1; |
|
554 notifyList.add(androidEvent.getUri()); |
|
555 } |
|
556 } else { |
|
557 rowDirty += 1; |
|
558 } |
|
559 } else { |
|
560 rowDirty += 1; |
|
561 } |
|
562 } |
|
563 } |
|
564 curEvent.close(); |
|
565 |
|
566 /*if ((rowInsert > 0) || (rowUpdate > 0) || (rowDelete > 0) || (rowDirty > 0)) { |
|
567 Log.i(TAG,"Android Rows inserted: " + String.valueOf(rowInsert)); |
|
568 Log.i(TAG,"Android Rows updated: " + String.valueOf(rowUpdate)); |
|
569 Log.i(TAG,"Android Rows deleted: " + String.valueOf(rowDelete)); |
|
570 Log.i(TAG,"Android Rows dirty: " + String.valueOf(rowDirty)); |
|
571 }*/ |
|
572 |
|
573 stats.numInserts += rowInsert; |
|
574 stats.numUpdates += rowUpdate; |
|
575 stats.numDeletes += rowDelete; |
|
576 stats.numSkippedEntries += rowDirty; |
|
577 stats.numEntries += rowInsert + rowUpdate + rowDelete; |
|
578 } catch (RemoteException e) { |
|
579 e.printStackTrace(); |
|
580 } catch (URISyntaxException e) { |
|
581 // TODO Automatisch generierter Erfassungsblock |
|
582 e.printStackTrace(); |
|
583 } catch (ClientProtocolException e) { |
|
584 // TODO Automatisch generierter Erfassungsblock |
|
585 e.printStackTrace(); |
|
586 } catch (IOException e) { |
|
587 // TODO Automatisch generierter Erfassungsblock |
|
588 e.printStackTrace(); |
|
589 } catch (CaldavProtocolException e) { |
|
590 // TODO Automatisch generierter Erfassungsblock |
|
591 e.printStackTrace(); |
|
592 } catch (ParserException e) { |
|
593 // TODO Automatisch generierter Erfassungsblock |
|
594 e.printStackTrace(); |
|
595 } |
|
596 |
|
597 return rowDirty; |
|
598 } |
|
599 |
|
600 /* private Account UpgradeAccount(Account OldAccount) { |
|
601 String Username = OldAccount.name; |
|
602 String Type = OldAccount.type; |
|
603 String Password = this.mAccountManager.getPassword(OldAccount); |
|
604 String Url = this.mAccountManager.getUserData(OldAccount, AuthenticatorActivity.USER_DATA_URL_KEY); |
|
605 |
|
606 Account NewAccount = new Account(Username + AuthenticatorActivity.ACCOUNT_NAME_SPLITTER + Url, Type); |
|
607 if (this.mAccountManager.addAccountExplicitly(NewAccount, Password, null)) { |
|
608 this.mAccountManager.setUserData(NewAccount, AuthenticatorActivity.USER_DATA_URL_KEY, Url); |
|
609 this.mAccountManager.setUserData(NewAccount, AuthenticatorActivity.USER_DATA_USERNAME, Username); |
|
610 } |
|
611 this.mAccountManager.removeAccount(OldAccount, null, null); |
|
612 |
|
613 return NewAccount; |
|
614 }*/ |
|
615 |
|
616 /* private void dropAllEvents(Account account, ContentProviderClient provider, Uri calendarUri) throws RemoteException { |
|
617 |
|
618 Log.i(TAG, "Deleting all calendar events for "+calendarUri); |
|
619 |
|
620 String selection = "(" + Events.CALENDAR_ID + " = ?)"; |
|
621 String[] selectionArgs = new String[] {Long.toString(ContentUris.parseId(calendarUri))}; |
|
622 |
|
623 provider.delete(asSyncAdapter(Events.CONTENT_URI, account.name, account.type), |
|
624 selection, selectionArgs); |
|
625 |
|
626 }*/ |
|
627 |
|
628 private static Uri asSyncAdapter(Uri uri, String account, String accountType) { |
|
629 return uri.buildUpon() |
|
630 .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true") |
|
631 .appendQueryParameter(Calendars.ACCOUNT_NAME, account) |
|
632 .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build(); |
|
633 } |
|
634 |
|
635 } |
|
636 |