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.

     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  */
    22 package org.gege.caldavsyncadapter.syncadapter;
    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;
    31 import javax.xml.parsers.ParserConfigurationException;
    33 import net.fortuna.ical4j.data.ParserException;
    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;
    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;
    69 public class SyncAdapter extends AbstractThreadedSyncAdapter {
    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;
    78 	private int mCountProviderFailedMax = 3;
    79 //	private Context mContext;
    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 	};*/
    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 */
    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 */
   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;
   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 	}
   123 	@Override
   124 	public void onPerformSync(Account account, Bundle extras, String authority,
   125 			ContentProviderClient provider, SyncResult syncResult) {
   126 		boolean bolError = false;
   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);
   132 		CalendarList serverCalList;
   134 		CalendarList androidCalList = new CalendarList(account, provider, CalendarSource.Android, url);
   135 		androidCalList.readCalendarFromClient();
   136 		ArrayList<Uri> notifyList = new ArrayList<Uri>();
   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 			}
   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");
   155 			for (DavCalendar serverCalendar : serverCalList.getCalendarList()) {
   156 				Log.i(TAG, "Detected calendar name=" + serverCalendar.getCalendarDisplayName() + " URI=" + serverCalendar.getURI());
   158 				Uri androidCalendarUri = serverCalendar.checkAndroidCalendarList(androidCalList, this.getContext());
   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);
   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);
   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");
   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 						 */
   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);
   195 				        countCursor.moveToFirst();
   196 				        int count = countCursor.getInt(0);
   197 				        syncResult.stats.numSkippedEntries += count;
   198 				        countCursor.close();*/
   200 					}
   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 			}
   218 			if (!bolError) {
   219 				// check whether a calendar is not synced -> delete it at android
   220 				androidCalList.deleteCalendarOnClientSideOnly(this.getContext());
   221 			}
   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 			}
   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));
   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 	}
   277 	public void onSyncCanceled () {
   278 		//TODO: implement SyncCanceled
   279 		this.mCountSyncCanceled += 1;
   280 		Log.v(TAG, "onSyncCanceled() count:" + String.valueOf(this.mCountSyncCanceled));
   281 	}
   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 {
   311 		/*if (DROP_CALENDAR_EVENTS) {
   312 			dropAllEvents(account, provider, androidCalendar.getAndroidCalendarUri());
   313 		}*/
   315 		int rowInsert = 0;
   316 		int rowUpdate = 0;
   317 		int rowTag = 0;
   318 		int rowDelete = 0;
   319 		int rowUntag = 0;
   320 		int rowSkip = 0;
   322 		for (CalendarEvent calendarEvent : serverCalendar.getCalendarEvents()) {
   323 			try {
   324 				AndroidEvent androidEvent = calendarEvent.getAndroidEvent(androidCalendar);
   326 				Log.i(TAG, "Event " + calendarEvent.getUri().toString()+ " androidUri="+androidEvent);
   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;
   359 			} catch (ParserException ex) {
   360 				Log.e(TAG, "Parser exception", ex);
   361 				stats.numParseExceptions++;
   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++;
   369 	            NotificationsHelper.signalSyncErrors(getContext(), "Caldav sync error (caldav)", ex.getMessage());
   370 	            //NotificationsHelper.getCurrentSyncLog().addException(ex);
   371 			}
   372 		}
   374 		rowDelete = androidCalendar.deleteUntaggedEvents();
   375 		rowUntag = androidCalendar.untagAndroidEvents();
   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));
   386 		stats.numInserts += rowInsert;
   387 		stats.numUpdates += rowUpdate;
   388 		stats.numDeletes += rowDelete;
   389 		stats.numSkippedEntries += rowSkip;
   390 		stats.numEntries += rowInsert + rowUpdate + rowDelete;
   392 	}
   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;
   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);
   433 			while (curEvent.moveToNext()) {
   434 				EventID = curEvent.getLong(curEvent.getColumnIndex(Events._ID));
   435 				Uri returnedUri = ContentUris.withAppendedId(Events.CONTENT_URI, EventID);
   437 				//androidEvent = new AndroidEvent(account, provider, returnedUri, calendarUri);
   438 				androidEvent = new AndroidEvent(returnedUri, calendarUri);
   439 				androidEvent.readContentValues(curEvent);
   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();
   452 				String SyncID = androidEvent.ContentValues.getAsString(Events._SYNC_ID);
   454 				boolean Deleted = false;
   455 				int intDeleted = 0;
   456 				intDeleted = curEvent.getInt(curEvent.getColumnIndex(Events.DELETED));
   457 				Deleted = (intDeleted == 1);
   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 += "/";
   466 					SyncID = calendarPath + newGUID + ".ics";
   468 					androidEvent.createIcs(newGUID);
   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);
   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());
   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)};
   507 						int countDeleted = provider.delete(asSyncAdapter(Events.CONTENT_URI, account.name, account.type), mSelectionClause, mSelectionArgs);	
   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);
   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);
   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);
   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();
   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 			}*/
   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 		}
   597 		return rowDirty;
   598 	}
   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);
   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);
   613 		return NewAccount;
   614 	}*/
   616 /*	private void dropAllEvents(Account account, ContentProviderClient provider,	Uri calendarUri) throws RemoteException {
   618 		Log.i(TAG, "Deleting all calendar events for "+calendarUri);
   620 		String selection = "(" + Events.CALENDAR_ID + " = ?)";
   621 		String[] selectionArgs = new String[] {Long.toString(ContentUris.parseId(calendarUri))}; 
   623 		provider.delete(asSyncAdapter(Events.CONTENT_URI, account.name, account.type), 
   624 				        selection, selectionArgs);
   626 	}*/
   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 	 }
   635 }

mercurial