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

Tue, 10 Feb 2015 18:12:00 +0100

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

Import initial revisions of existing project AndroidCaldavSyncAdapater,
forked from upstream repository at 27e8a0f8495c92e0780d450bdf0c7cec77a03a55.

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

mercurial