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

changeset 0
fb9019fb1bf7
child 8
ec8af0e3fbc2
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/org/gege/caldavsyncadapter/syncadapter/SyncAdapter.java	Tue Feb 10 18:12:00 2015 +0100
     1.3 @@ -0,0 +1,636 @@
     1.4 +/**
     1.5 + * Copyright (c) 2012-2013, Gerald Garcia, David Wiesner, Timo Berger
     1.6 + * 
     1.7 + * This file is part of Andoid Caldav Sync Adapter Free.
     1.8 + *
     1.9 + * Andoid Caldav Sync Adapter Free is free software: you can redistribute 
    1.10 + * it and/or modify it under the terms of the GNU General Public License 
    1.11 + * as published by the Free Software Foundation, either version 3 of the 
    1.12 + * License, or at your option any later version.
    1.13 + *
    1.14 + * Andoid Caldav Sync Adapter Free is distributed in the hope that 
    1.15 + * it will be useful, but WITHOUT ANY WARRANTY; without even the implied 
    1.16 + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.17 + * GNU General Public License for more details.
    1.18 + *
    1.19 + * You should have received a copy of the GNU General Public License
    1.20 + * along with Andoid Caldav Sync Adapter Free.  
    1.21 + * If not, see <http://www.gnu.org/licenses/>.
    1.22 + * 
    1.23 + */
    1.24 +
    1.25 +package org.gege.caldavsyncadapter.syncadapter;
    1.26 +
    1.27 +import java.io.IOException;
    1.28 +import java.net.URI;
    1.29 +//import java.net.MalformedURLException;
    1.30 +import java.net.URISyntaxException;
    1.31 +import java.util.ArrayList;
    1.32 +//import java.security.GeneralSecurityException;
    1.33 +
    1.34 +import javax.xml.parsers.ParserConfigurationException;
    1.35 +
    1.36 +import net.fortuna.ical4j.data.ParserException;
    1.37 +
    1.38 +import org.apache.http.ParseException;
    1.39 +import org.apache.http.client.ClientProtocolException;
    1.40 +import org.gege.caldavsyncadapter.Event;
    1.41 +import org.gege.caldavsyncadapter.android.entities.AndroidEvent;
    1.42 +import org.gege.caldavsyncadapter.authenticator.AuthenticatorActivity;
    1.43 +import org.gege.caldavsyncadapter.caldav.CaldavFacade;
    1.44 +import org.gege.caldavsyncadapter.caldav.CaldavProtocolException;
    1.45 +import org.gege.caldavsyncadapter.caldav.entities.DavCalendar;
    1.46 +import org.gege.caldavsyncadapter.caldav.entities.CalendarEvent;
    1.47 +import org.gege.caldavsyncadapter.caldav.entities.CalendarList;
    1.48 +import org.gege.caldavsyncadapter.caldav.entities.DavCalendar.CalendarSource;
    1.49 +import org.gege.caldavsyncadapter.syncadapter.notifications.NotificationsHelper;
    1.50 +import org.xml.sax.SAXException;
    1.51 +
    1.52 +import android.accounts.Account;
    1.53 +import android.accounts.AccountManager;
    1.54 +import android.content.AbstractThreadedSyncAdapter;
    1.55 +import android.content.ContentProviderClient;
    1.56 +import android.content.ContentUris;
    1.57 +import android.content.ContentValues;
    1.58 +import android.content.Context;
    1.59 +import android.content.SyncResult;
    1.60 +import android.content.SyncStats;
    1.61 +import android.content.pm.PackageManager.NameNotFoundException;
    1.62 +import android.database.Cursor;
    1.63 +import android.net.Uri;
    1.64 +import android.os.Bundle;
    1.65 +import android.os.RemoteException;
    1.66 +import android.provider.CalendarContract.Attendees;
    1.67 +import android.provider.CalendarContract.Calendars;
    1.68 +import android.provider.CalendarContract.Events;
    1.69 +import android.provider.CalendarContract.Reminders;
    1.70 +import android.util.Log;
    1.71 +
    1.72 +public class SyncAdapter extends AbstractThreadedSyncAdapter {
    1.73 +
    1.74 +	private static final String TAG = "SyncAdapter";
    1.75 +	private AccountManager mAccountManager;
    1.76 +	private String mVersion = "";
    1.77 +	private int mCountPerformSync = 0;
    1.78 +	private int mCountSyncCanceled = 0;
    1.79 +	private int mCountProviderFailed = 0;
    1.80 +	
    1.81 +	private int mCountProviderFailedMax = 3;
    1.82 +//	private Context mContext;
    1.83 +	
    1.84 +	
    1.85 +/*	private static final String[] CALENDAR_PROJECTION = new String[] {
    1.86 +	    Calendars._ID,                           // 0
    1.87 +	    Calendars.ACCOUNT_NAME,                  // 1
    1.88 +	    Calendars.CALENDAR_DISPLAY_NAME,         // 2
    1.89 +	    Calendars.OWNER_ACCOUNT,                 // 3
    1.90 +	    Calendar.CTAG                            // 4
    1.91 +	};*/
    1.92 +	  
    1.93 +/*	// The indices for the projection array above.
    1.94 +	private static final int PROJECTION_ID_INDEX = 0;
    1.95 +	private static final int PROJECTION_ACCOUNT_NAME_INDEX = 1;
    1.96 +	private static final int PROJECTION_DISPLAY_NAME_INDEX = 2;
    1.97 +	private static final int PROJECTION_OWNER_ACCOUNT_INDEX = 3;
    1.98 +*/
    1.99 +	
   1.100 +/*
   1.101 +	private static final String[] EVENT_PROJECTION = new String[] {
   1.102 +		Events._ID,
   1.103 +		Events._SYNC_ID,
   1.104 +		Events.SYNC_DATA1,
   1.105 +		Events.CALENDAR_ID
   1.106 +	};
   1.107 +*/
   1.108 +	
   1.109 +	// ignore same CTag
   1.110 +	//private static final boolean FORCE_SYNCHRONIZE = false;
   1.111 +	// drop all calendar before synchro
   1.112 +	//private static final boolean DROP_CALENDAR_EVENTS = false;
   1.113 +	
   1.114 +	public SyncAdapter(Context context, boolean autoInitialize) {
   1.115 +		super(context, autoInitialize);
   1.116 +		//android.os.Debug.waitForDebugger();
   1.117 +		mAccountManager = AccountManager.get(context);
   1.118 +		try {
   1.119 +			mVersion = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
   1.120 +		} catch (NameNotFoundException e) {
   1.121 +			e.printStackTrace();
   1.122 +		}
   1.123 +//		mContext = context;
   1.124 +	}
   1.125 +
   1.126 +	@Override
   1.127 +	public void onPerformSync(Account account, Bundle extras, String authority,
   1.128 +			ContentProviderClient provider, SyncResult syncResult) {
   1.129 +		boolean bolError = false;
   1.130 +		
   1.131 +		String url = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_URL_KEY);
   1.132 +		this.mCountPerformSync += 1;
   1.133 +		Log.v(TAG, "onPerformSync() count:" + String.valueOf(this.mCountPerformSync) + " on " + account.name + " with URL " + url);
   1.134 +
   1.135 +		CalendarList serverCalList;
   1.136 +		
   1.137 +		CalendarList androidCalList = new CalendarList(account, provider, CalendarSource.Android, url);
   1.138 +		androidCalList.readCalendarFromClient();
   1.139 +		ArrayList<Uri> notifyList = new ArrayList<Uri>();
   1.140 +
   1.141 +		try {
   1.142 + 			String Username = "";
   1.143 +			String UserDataVersion = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_VERSION);
   1.144 +			if (UserDataVersion == null) {
   1.145 +				Username = account.name;
   1.146 +			} else {
   1.147 +				Username = mAccountManager.getUserData(account, AuthenticatorActivity.USER_DATA_USERNAME);
   1.148 +			}
   1.149 +
   1.150 +			CaldavFacade facade = new CaldavFacade(Username, mAccountManager.getPassword(account), url);
   1.151 +			facade.setAccount(account);
   1.152 +			facade.setProvider(provider);
   1.153 +			facade.setVersion(mVersion);
   1.154 +			serverCalList = facade.getCalendarList(this.getContext());
   1.155 +			//String davProperties = facade.getLastDav();
   1.156 +			Log.i(TAG, String.valueOf(androidCalList.getCalendarList().size()) + " calendars found at android");
   1.157 +			
   1.158 +			for (DavCalendar serverCalendar : serverCalList.getCalendarList()) {
   1.159 +				Log.i(TAG, "Detected calendar name=" + serverCalendar.getCalendarDisplayName() + " URI=" + serverCalendar.getURI());
   1.160 +
   1.161 +				Uri androidCalendarUri = serverCalendar.checkAndroidCalendarList(androidCalList, this.getContext());
   1.162 +
   1.163 +				// check if the adapter was able to get an existing calendar or create a new one
   1.164 +				if (androidCalendarUri != null) {
   1.165 +					// the provider seems to work correct, reset the counter
   1.166 +					mCountProviderFailed = 0;
   1.167 +					DavCalendar androidCalendar = androidCalList.getCalendarByAndroidUri(androidCalendarUri);
   1.168 +					
   1.169 +					//if ((FORCE_SYNCHRONIZE) || (androidCalendar.getcTag() == null) || (!androidCalendar.getcTag().equals(serverCalendar.getcTag()))) {
   1.170 +					if ((androidCalendar.getcTag() == null) || (!androidCalendar.getcTag().equals(serverCalendar.getcTag()))) {
   1.171 +							Log.d(TAG, "CTag has changed, something to synchronise");
   1.172 +							if (serverCalendar.readCalendarEvents(facade)) {
   1.173 +								this.synchroniseEvents(androidCalendar, serverCalendar, syncResult.stats, notifyList);
   1.174 +
   1.175 +								Log.d(TAG, "Updating stored CTag");
   1.176 +								//serverCalendar.updateAndroidCalendar(androidCalendarUri, Calendar.CTAG, serverCalendar.getcTag());
   1.177 +								androidCalendar.setCTag(serverCalendar.getcTag(), true);
   1.178 +							} else {
   1.179 +								Log.d(TAG, "unable to read events from server calendar");
   1.180 +							}
   1.181 +					} else {
   1.182 +						Log.d(TAG, "CTag has not changed, nothing to do");
   1.183 +	
   1.184 +						/* this is unnecessary. "SkippedEntries" are:
   1.185 +						 * Counter for tracking how many entries, either from the server or the local store, 
   1.186 +						 * were ignored during the sync operation. This could happen if the SyncAdapter detected 
   1.187 +						 * some unparsable data but decided to skip it and move on rather than failing immediately. 
   1.188 +						 */
   1.189 +						
   1.190 +						/*long CalendarID = ContentUris.parseId(androidCalendarUri);
   1.191 +						String selection = "(" + Events.CALENDAR_ID + " = ?)";
   1.192 +						String[] selectionArgs = new String[] {String.valueOf(CalendarID)}; 
   1.193 +						Cursor countCursor = provider.query(Events.CONTENT_URI, new String[] {"count(*) AS count"},
   1.194 +					                selection,
   1.195 +					                selectionArgs,
   1.196 +					                null);
   1.197 +	
   1.198 +				        countCursor.moveToFirst();
   1.199 +				        int count = countCursor.getInt(0);
   1.200 +				        syncResult.stats.numSkippedEntries += count;
   1.201 +				        countCursor.close();*/
   1.202 +						
   1.203 +					}
   1.204 +					
   1.205 +					this.checkDirtyAndroidEvents(provider, account, androidCalendarUri, facade, serverCalendar.getURI(), syncResult.stats, notifyList);
   1.206 +				} else {
   1.207 +					// this happens if the data provider failes to get an existing or create a new calendar
   1.208 +					mCountProviderFailed += 1;
   1.209 +					Log.e(TAG, "failed to get an existing or create a new calendar");
   1.210 +					syncResult.stats.numIoExceptions += 1;
   1.211 +					if (mCountProviderFailed >= mCountProviderFailedMax) {
   1.212 +						// see issue #96
   1.213 +						NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (provider failed)", "are you using CyanogenMod in Incognito Mode?");
   1.214 +					} else {
   1.215 +						NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (provider failed)", "the provider failed to get an existing or create a new calendar");
   1.216 +					}
   1.217 +					bolError = true;
   1.218 +				}
   1.219 +			}
   1.220 +			
   1.221 +			if (!bolError) {
   1.222 +				// check whether a calendar is not synced -> delete it at android
   1.223 +				androidCalList.deleteCalendarOnClientSideOnly(this.getContext());
   1.224 +			}
   1.225 +			
   1.226 +			// notify the ContentResolver
   1.227 +			for (Uri uri : androidCalList.getNotifyList()) {
   1.228 +				this.getContext().getContentResolver().notifyChange(uri, null);
   1.229 +			}
   1.230 +			for (Uri uri : serverCalList.getNotifyList()) {
   1.231 +				this.getContext().getContentResolver().notifyChange(uri, null);
   1.232 +			}
   1.233 +			for (Uri uri : notifyList) {
   1.234 +				this.getContext().getContentResolver().notifyChange(uri, null);
   1.235 +			}
   1.236 +			
   1.237 +			//Log.i(TAG,"Statistiks for Calendar: " + serverCalendar.getURI().toString());
   1.238 +			//Log.i(TAG,"Statistiks for AndroidCalendar: " + androidCalendar.getAndroidCalendarUri().toString());
   1.239 +			Log.i(TAG,"Entries:                       " + String.valueOf(syncResult.stats.numEntries));
   1.240 +			Log.i(TAG,"Rows inserted:                 " + String.valueOf(syncResult.stats.numInserts));
   1.241 +			Log.i(TAG,"Rows updated:                  " + String.valueOf(syncResult.stats.numUpdates));
   1.242 +			Log.i(TAG,"Rows deleted:                  " + String.valueOf(syncResult.stats.numDeletes));
   1.243 +			Log.i(TAG,"Rows skipped:                  " + String.valueOf(syncResult.stats.numSkippedEntries));
   1.244 +			Log.i(TAG,"Io Exceptions:                 " + String.valueOf(syncResult.stats.numIoExceptions));
   1.245 +			Log.i(TAG,"Parse Exceptions:              " + String.valueOf(syncResult.stats.numParseExceptions));
   1.246 +			Log.i(TAG,"Auth Exceptions:               " + String.valueOf(syncResult.stats.numAuthExceptions));
   1.247 +			Log.i(TAG,"Conflict Detected Exceptions:  " + String.valueOf(syncResult.stats.numConflictDetectedExceptions));
   1.248 +
   1.249 +		/*} catch (final AuthenticatorException e) {
   1.250 +            syncResult.stats.numParseExceptions++;
   1.251 +            Log.e(TAG, "AuthenticatorException", e);*/
   1.252 +        /*} catch (final OperationCanceledException e) {
   1.253 +            Log.e(TAG, "OperationCanceledExcetpion", e);*/
   1.254 +        } catch (final IOException e) {
   1.255 +            Log.e(TAG, "IOException", e);
   1.256 +            syncResult.stats.numIoExceptions++;
   1.257 +            NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (IO)", e.getMessage());
   1.258 +            //NotificationsHelper.getCurrentSyncLog().addException(e);
   1.259 +            /*} catch (final AuthenticationException e) {
   1.260 +            //mAccountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE, authtoken);
   1.261 +            syncResult.stats.numAuthExceptions++;
   1.262 +            Log.e(TAG, "AuthenticationException", e);*/
   1.263 +        } catch (final ParseException e) {
   1.264 +            syncResult.stats.numParseExceptions++;
   1.265 +            Log.e(TAG, "ParseException", e);
   1.266 +            NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (parsing)", e.getMessage());
   1.267 +            //NotificationsHelper.getCurrentSyncLog().addException(e);
   1.268 +        /*} catch (final JSONException e) {
   1.269 +            syncResult.stats.numParseExceptions++;
   1.270 +            Log.e(TAG, "JSONException", e);*/
   1.271 +		} catch (Exception e) {
   1.272 +			Log.e(TAG, "Updating calendar exception " + e.getClass().getName(), e);
   1.273 +            syncResult.stats.numParseExceptions++;
   1.274 +            NotificationsHelper.signalSyncErrors(this.getContext(), "Caldav sync error (general)", e.getMessage());
   1.275 +            //NotificationsHelper.getCurrentSyncLog().addException(e);
   1.276 +			//throw new RuntimeException(e);
   1.277 +		}
   1.278 +	}
   1.279 +
   1.280 +	public void onSyncCanceled () {
   1.281 +		//TODO: implement SyncCanceled
   1.282 +		this.mCountSyncCanceled += 1;
   1.283 +		Log.v(TAG, "onSyncCanceled() count:" + String.valueOf(this.mCountSyncCanceled));
   1.284 +	}
   1.285 +
   1.286 +	
   1.287 +	/**
   1.288 +	 * both calender event and android event have been found.
   1.289 +	 * server wins always at the moment.
   1.290 +	 * @param androidCalendar
   1.291 +	 * @param serverCalendar
   1.292 +	 * @param stats
   1.293 +	 * @param notifyList
   1.294 +	 * @throws ClientProtocolException
   1.295 +	 * @throws URISyntaxException
   1.296 +	 * @throws IOException
   1.297 +	 * @throws ParserConfigurationException
   1.298 +	 * @throws SAXException
   1.299 +	 * @throws RemoteException
   1.300 +	 * @throws CaldavProtocolException
   1.301 +	 * @throws ParserException
   1.302 +	 * @see SyncAdapter#updateAndroidEvent(ContentProviderClient, Account, AndroidEvent, CalendarEvent)
   1.303 +	 * @see SyncAdapter#tagAndroidEvent(ContentProviderClient, Account, AndroidEvent)
   1.304 +	 * @see SyncAdapter#untagAndroidEvents(ContentProviderClient, Account, Uri)
   1.305 +	 * @see SyncAdapter#deleteUntaggedEvents(ContentProviderClient, Account, Uri)
   1.306 +	 */
   1.307 +	private void synchroniseEvents(
   1.308 +				DavCalendar androidCalendar, 
   1.309 +				DavCalendar serverCalendar, 
   1.310 +				SyncStats stats, 
   1.311 +				ArrayList<Uri> notifyList
   1.312 +			) throws ClientProtocolException, URISyntaxException, IOException, ParserConfigurationException, SAXException, RemoteException, CaldavProtocolException, ParserException {
   1.313 +		
   1.314 +		/*if (DROP_CALENDAR_EVENTS) {
   1.315 +			dropAllEvents(account, provider, androidCalendar.getAndroidCalendarUri());
   1.316 +		}*/
   1.317 +		
   1.318 +		int rowInsert = 0;
   1.319 +		int rowUpdate = 0;
   1.320 +		int rowTag = 0;
   1.321 +		int rowDelete = 0;
   1.322 +		int rowUntag = 0;
   1.323 +		int rowSkip = 0;
   1.324 +		
   1.325 +		for (CalendarEvent calendarEvent : serverCalendar.getCalendarEvents()) {
   1.326 +			try {
   1.327 +				AndroidEvent androidEvent = calendarEvent.getAndroidEvent(androidCalendar);
   1.328 +				
   1.329 +				Log.i(TAG, "Event " + calendarEvent.getUri().toString()+ " androidUri="+androidEvent);
   1.330 +				
   1.331 +				if (androidEvent == null) {
   1.332 +					/* new android event */
   1.333 +					if (calendarEvent.createAndroidEvent(androidCalendar)) {
   1.334 +						rowInsert += 1;
   1.335 +						androidEvent = calendarEvent.getAndroidEvent(androidCalendar);
   1.336 +						notifyList.add(androidEvent.getUri());
   1.337 +					} else {
   1.338 +						rowSkip += 1;
   1.339 +					}
   1.340 +				} else {
   1.341 +					/* the android exists */
   1.342 +					String androidETag = androidEvent.getETag();
   1.343 +					if (androidETag == null)
   1.344 +						androidETag = "";
   1.345 +					Log.d(TAG, "Event compare: " + androidETag + " <> " + calendarEvent.getETag().toString());
   1.346 +					if ((androidEvent.getETag() == null) || (!androidETag.equals(calendarEvent.getETag()))) {
   1.347 +						/* the android event is getting updated */
   1.348 +						if (calendarEvent.updateAndroidEvent(androidEvent)) {
   1.349 +							rowUpdate += 1;
   1.350 +							notifyList.add(androidEvent.getUri());
   1.351 +						} else {
   1.352 +							rowSkip += 1;
   1.353 +						}
   1.354 +					}
   1.355 +				}
   1.356 +				if (androidEvent != null)
   1.357 +					//if (androidEvent.tagAndroidEvent())
   1.358 +					if (androidCalendar.tagAndroidEvent(androidEvent))
   1.359 +						rowTag += 1;
   1.360 +				
   1.361 +				
   1.362 +			} catch (ParserException ex) {
   1.363 +				Log.e(TAG, "Parser exception", ex);
   1.364 +				stats.numParseExceptions++;
   1.365 +
   1.366 +	            NotificationsHelper.signalSyncErrors(getContext(), "Caldav sync error (parsing)", ex.getMessage());
   1.367 +	            //NotificationsHelper.getCurrentSyncLog().addException(ex);
   1.368 +			} catch (CaldavProtocolException ex) {
   1.369 +				Log.e(TAG, "Caldav exception", ex);
   1.370 +				stats.numParseExceptions++;
   1.371 +
   1.372 +	            NotificationsHelper.signalSyncErrors(getContext(), "Caldav sync error (caldav)", ex.getMessage());
   1.373 +	            //NotificationsHelper.getCurrentSyncLog().addException(ex);
   1.374 +			}
   1.375 +		}
   1.376 +		
   1.377 +		rowDelete = androidCalendar.deleteUntaggedEvents();
   1.378 +		rowUntag = androidCalendar.untagAndroidEvents();
   1.379 +
   1.380 +		/*Log.i(TAG,"Statistiks for Calendar: " + serverCalendar.getURI().toString());
   1.381 +		Log.i(TAG,"Statistiks for AndroidCalendar: " + androidCalendar.getAndroidCalendarUri().toString());
   1.382 +		Log.i(TAG,"Rows inserted: " + String.valueOf(rowInsert));
   1.383 +		Log.i(TAG,"Rows updated:  " + String.valueOf(rowUpdate));
   1.384 +		Log.i(TAG,"Rows deleted:  " + String.valueOf(rowDelete));
   1.385 +		Log.i(TAG,"Rows skipped:  " + String.valueOf(rowSkip));*/
   1.386 +		Log.i(TAG,"Rows tagged:   " + String.valueOf(rowTag));
   1.387 +		Log.i(TAG,"Rows untagged: " + String.valueOf(rowUntag));
   1.388 +		
   1.389 +		stats.numInserts += rowInsert;
   1.390 +		stats.numUpdates += rowUpdate;
   1.391 +		stats.numDeletes += rowDelete;
   1.392 +		stats.numSkippedEntries += rowSkip;
   1.393 +		stats.numEntries += rowInsert + rowUpdate + rowDelete;
   1.394 +
   1.395 +	}
   1.396 +	
   1.397 +	/**
   1.398 +	 * checks the android events for the dirty flag.
   1.399 +	 * the flag is set by android when the event has been changed. 
   1.400 +	 * the dirty flag is removed when an android event has been updated from calendar event
   1.401 +	 * @param provider
   1.402 +	 * @param account
   1.403 +	 * @param calendarUri
   1.404 +	 * @param facade
   1.405 +	 * @param caldavCalendarUri
   1.406 +	 * @param stats
   1.407 +	 * @param notifyList
   1.408 +	 * @return count of dirty events
   1.409 +	 */
   1.410 +	private int checkDirtyAndroidEvents(
   1.411 +				ContentProviderClient provider, 
   1.412 +				Account account, 
   1.413 +				Uri calendarUri, 
   1.414 +				CaldavFacade facade, 
   1.415 +				URI caldavCalendarUri, 
   1.416 +				SyncStats stats, 
   1.417 +				ArrayList<Uri> notifyList
   1.418 +			) {
   1.419 +		Cursor curEvent = null;
   1.420 +		Cursor curAttendee = null;
   1.421 +		Cursor curReminder = null;
   1.422 +		Long EventID;
   1.423 +		Long CalendarID;
   1.424 +		AndroidEvent androidEvent = null;
   1.425 +		int rowDirty = 0;
   1.426 +		int rowInsert = 0;
   1.427 +		int rowUpdate = 0;
   1.428 +		int rowDelete = 0;
   1.429 +		
   1.430 +		try {
   1.431 +			CalendarID = ContentUris.parseId(calendarUri);
   1.432 +			String selection = "(" + Events.DIRTY + " = ?) AND (" + Events.CALENDAR_ID + " = ?)";
   1.433 +			String[] selectionArgs = new String[] {"1", CalendarID.toString()}; 
   1.434 +			curEvent = provider.query(Events.CONTENT_URI, null, selection, selectionArgs, null);
   1.435 +			
   1.436 +			while (curEvent.moveToNext()) {
   1.437 +				EventID = curEvent.getLong(curEvent.getColumnIndex(Events._ID));
   1.438 +				Uri returnedUri = ContentUris.withAppendedId(Events.CONTENT_URI, EventID);
   1.439 +				
   1.440 +				//androidEvent = new AndroidEvent(account, provider, returnedUri, calendarUri);
   1.441 +				androidEvent = new AndroidEvent(returnedUri, calendarUri);
   1.442 +				androidEvent.readContentValues(curEvent);
   1.443 +				
   1.444 +				selection = "(" + Attendees.EVENT_ID + " = ?)";
   1.445 +				selectionArgs = new String[] {String.valueOf(EventID)};
   1.446 +				curAttendee = provider.query(Attendees.CONTENT_URI, null, selection, selectionArgs, null);
   1.447 +				selection = "(" + Reminders.EVENT_ID + " = ?)";
   1.448 +				selectionArgs = new String[] {String.valueOf(EventID)};
   1.449 +				curReminder = provider.query(Reminders.CONTENT_URI, null, selection, selectionArgs, null);
   1.450 +				androidEvent.readAttendees(curAttendee);
   1.451 +				androidEvent.readReminder(curReminder);
   1.452 +				curAttendee.close();
   1.453 +				curReminder.close();
   1.454 +				
   1.455 +				String SyncID = androidEvent.ContentValues.getAsString(Events._SYNC_ID);
   1.456 +				
   1.457 +				boolean Deleted = false;
   1.458 +				int intDeleted = 0;
   1.459 +				intDeleted = curEvent.getInt(curEvent.getColumnIndex(Events.DELETED));
   1.460 +				Deleted = (intDeleted == 1);
   1.461 +
   1.462 +				if (SyncID == null) {
   1.463 +					// new Android event
   1.464 +					String newGUID = java.util.UUID.randomUUID().toString() + "-caldavsyncadapter";
   1.465 +					String calendarPath = caldavCalendarUri.getPath();
   1.466 +					if (!calendarPath.endsWith("/"))
   1.467 +						calendarPath += "/";
   1.468 +
   1.469 +					SyncID = calendarPath + newGUID + ".ics";
   1.470 +					
   1.471 +					androidEvent.createIcs(newGUID);
   1.472 +					
   1.473 +					if (facade.createEvent(URI.create(SyncID), androidEvent.getIcsEvent().toString())) {
   1.474 +						//HINT: bugfix for google calendar replace("@", "%40")
   1.475 +						if (SyncID.contains("@"))
   1.476 +							SyncID = SyncID.replace("@", "%40");
   1.477 +						ContentValues values = new ContentValues();
   1.478 +						values.put(Events._SYNC_ID, SyncID);
   1.479 +
   1.480 +						//google doesn't send the etag after creation
   1.481 +						//HINT: my SabreDAV send always the same etag after putting a new event
   1.482 +						//String LastETag = facade.getLastETag();
   1.483 +						//if (!LastETag.equals("")) {
   1.484 +						//	values.put(Event.ETAG, LastETag);
   1.485 +						//} else {
   1.486 +							//so get the etag with a new REPORT
   1.487 +							CalendarEvent calendarEvent = new CalendarEvent(account, provider);
   1.488 +							calendarEvent.calendarURL = caldavCalendarUri.toURL();
   1.489 +							URI SyncURI = new URI(SyncID);
   1.490 +							calendarEvent.setUri(SyncURI);
   1.491 +							CaldavFacade.getEvent(calendarEvent);
   1.492 +							values.put(Event.ETAG, calendarEvent.getETag());
   1.493 +						//}
   1.494 +						values.put(Event.UID, newGUID);
   1.495 +						values.put(Events.DIRTY, 0);
   1.496 +						values.put(Event.RAWDATA, androidEvent.getIcsEvent().toString());
   1.497 +						
   1.498 +						int rowCount = provider.update(asSyncAdapter(androidEvent.getUri(), account.name, account.type), values, null, null);
   1.499 +						if (rowCount == 1) {
   1.500 +							rowInsert += 1;
   1.501 +							notifyList.add(androidEvent.getUri());
   1.502 +						}
   1.503 +					}
   1.504 +				} else if (Deleted) {
   1.505 +					// deleted Android event
   1.506 +					if (facade.deleteEvent(URI.create(SyncID), androidEvent.getETag())) {
   1.507 +						String mSelectionClause = "(" + Events._ID +  "= ?)";
   1.508 +						String[] mSelectionArgs = {String.valueOf(EventID)};
   1.509 +						
   1.510 +						int countDeleted = provider.delete(asSyncAdapter(Events.CONTENT_URI, account.name, account.type), mSelectionClause, mSelectionArgs);	
   1.511 +						
   1.512 +						if (countDeleted == 1) {
   1.513 +							rowDelete += 1;
   1.514 +							notifyList.add(androidEvent.getUri());
   1.515 +						}
   1.516 +					}
   1.517 +				} else {
   1.518 +					//update the android event to the server
   1.519 +					String uid = androidEvent.getUID();
   1.520 +					if ((uid == null) || (uid.equals(""))) {
   1.521 +						//COMPAT: this is needed because in the past, the UID was not stored in the android event
   1.522 +						CalendarEvent calendarEvent = new CalendarEvent(account, provider);
   1.523 +						URI syncURI = new URI(SyncID);
   1.524 +						calendarEvent.setUri(syncURI);
   1.525 +						calendarEvent.calendarURL = caldavCalendarUri.toURL();
   1.526 +						if (calendarEvent.fetchBody()) {
   1.527 +							calendarEvent.readContentValues();
   1.528 +							uid = calendarEvent.getUID();
   1.529 +						}
   1.530 +					}
   1.531 +					if (uid != null) {
   1.532 +						androidEvent.createIcs(uid);
   1.533 +							
   1.534 +						if (facade.updateEvent(URI.create(SyncID), androidEvent.getIcsEvent().toString(), androidEvent.getETag())) {
   1.535 +							selection = "(" + Events._ID + "= ?)";
   1.536 +							selectionArgs = new String[] {EventID.toString()};
   1.537 +							androidEvent.ContentValues.put(Events.DIRTY, 0);
   1.538 +
   1.539 +							//google doesn't send the etag after update
   1.540 +							String LastETag = facade.getLastETag();
   1.541 +							if (!LastETag.equals("")) {
   1.542 +								androidEvent.ContentValues.put(Event.ETAG, LastETag);
   1.543 +							} else {
   1.544 +								//so get the etag with a new REPORT
   1.545 +								CalendarEvent calendarEvent = new CalendarEvent(account, provider);
   1.546 +								calendarEvent.calendarURL = caldavCalendarUri.toURL();
   1.547 +								URI SyncURI = new URI(SyncID);
   1.548 +								calendarEvent.setUri(SyncURI);
   1.549 +								CaldavFacade.getEvent(calendarEvent);
   1.550 +								androidEvent.ContentValues.put(Event.ETAG, calendarEvent.getETag());
   1.551 +							}
   1.552 +							androidEvent.ContentValues.put(Event.RAWDATA, androidEvent.getIcsEvent().toString());
   1.553 +							int RowCount = provider.update(asSyncAdapter(androidEvent.getUri(), account.name, account.type), androidEvent.ContentValues, null, null);
   1.554 +			
   1.555 +							if (RowCount == 1) {
   1.556 +								rowUpdate += 1;
   1.557 +								notifyList.add(androidEvent.getUri());
   1.558 +							}
   1.559 +						} else {
   1.560 +							rowDirty += 1;
   1.561 +						}
   1.562 +					} else {
   1.563 +						rowDirty += 1;
   1.564 +					}
   1.565 +				}
   1.566 +			}
   1.567 +			curEvent.close();
   1.568 +
   1.569 +			/*if ((rowInsert > 0) || (rowUpdate > 0) || (rowDelete > 0) || (rowDirty > 0)) {
   1.570 +				Log.i(TAG,"Android Rows inserted: " + String.valueOf(rowInsert));
   1.571 +				Log.i(TAG,"Android Rows updated:  " + String.valueOf(rowUpdate));
   1.572 +				Log.i(TAG,"Android Rows deleted:  " + String.valueOf(rowDelete));
   1.573 +				Log.i(TAG,"Android Rows dirty:    " + String.valueOf(rowDirty));
   1.574 +			}*/
   1.575 +			
   1.576 +			stats.numInserts += rowInsert;
   1.577 +			stats.numUpdates += rowUpdate;
   1.578 +			stats.numDeletes += rowDelete;
   1.579 +			stats.numSkippedEntries += rowDirty;
   1.580 +			stats.numEntries += rowInsert + rowUpdate + rowDelete;
   1.581 +		} catch (RemoteException e) {
   1.582 +			e.printStackTrace();
   1.583 +		} catch (URISyntaxException e) {
   1.584 +			// TODO Automatisch generierter Erfassungsblock
   1.585 +			e.printStackTrace();
   1.586 +		} catch (ClientProtocolException e) {
   1.587 +			// TODO Automatisch generierter Erfassungsblock
   1.588 +			e.printStackTrace();
   1.589 +		} catch (IOException e) {
   1.590 +			// TODO Automatisch generierter Erfassungsblock
   1.591 +			e.printStackTrace();
   1.592 +		} catch (CaldavProtocolException e) {
   1.593 +			// TODO Automatisch generierter Erfassungsblock
   1.594 +			e.printStackTrace();
   1.595 +		} catch (ParserException e) {
   1.596 +			// TODO Automatisch generierter Erfassungsblock
   1.597 +			e.printStackTrace();
   1.598 +		}
   1.599 +		
   1.600 +		return rowDirty;
   1.601 +	}
   1.602 +	
   1.603 +/*	private Account UpgradeAccount(Account OldAccount) {
   1.604 +		String Username = OldAccount.name;
   1.605 +		String Type = OldAccount.type;
   1.606 +		String Password = this.mAccountManager.getPassword(OldAccount);
   1.607 +		String Url = this.mAccountManager.getUserData(OldAccount, AuthenticatorActivity.USER_DATA_URL_KEY);
   1.608 +
   1.609 +		Account NewAccount = new Account(Username + AuthenticatorActivity.ACCOUNT_NAME_SPLITTER + Url, Type);
   1.610 +		if (this.mAccountManager.addAccountExplicitly(NewAccount, Password, null)) {
   1.611 +			this.mAccountManager.setUserData(NewAccount, AuthenticatorActivity.USER_DATA_URL_KEY, Url);
   1.612 +			this.mAccountManager.setUserData(NewAccount, AuthenticatorActivity.USER_DATA_USERNAME, Username);
   1.613 +		}
   1.614 +		this.mAccountManager.removeAccount(OldAccount, null, null);
   1.615 +		
   1.616 +		return NewAccount;
   1.617 +	}*/
   1.618 +	
   1.619 +/*	private void dropAllEvents(Account account, ContentProviderClient provider,	Uri calendarUri) throws RemoteException {
   1.620 +		
   1.621 +		Log.i(TAG, "Deleting all calendar events for "+calendarUri);
   1.622 +		
   1.623 +		String selection = "(" + Events.CALENDAR_ID + " = ?)";
   1.624 +		String[] selectionArgs = new String[] {Long.toString(ContentUris.parseId(calendarUri))}; 
   1.625 +		
   1.626 +		provider.delete(asSyncAdapter(Events.CONTENT_URI, account.name, account.type), 
   1.627 +				        selection, selectionArgs);
   1.628 +		
   1.629 +	}*/
   1.630 +	
   1.631 +	private static Uri asSyncAdapter(Uri uri, String account, String accountType) {
   1.632 +	    return uri.buildUpon()
   1.633 +	        .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true")
   1.634 +	        .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
   1.635 +	        .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
   1.636 +	 }
   1.637 +
   1.638 +}
   1.639 +

mercurial