src/org/gege/caldavsyncadapter/syncadapter/SyncAdapter.java

Tue, 10 Feb 2015 22:40:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 10 Feb 2015 22:40:00 +0100
changeset 8
ec8af0e3fbc2
parent 0
fb9019fb1bf7
permissions
-rw-r--r--

Merge https://github.com/gggard/AndroidCaldavSyncAdapater/pull/206/

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

mercurial