diff -r 9250fd79cb4e -r ec8af0e3fbc2 src/org/gege/caldavsyncadapter/caldav/entities/DavCalendar.java --- a/src/org/gege/caldavsyncadapter/caldav/entities/DavCalendar.java Tue Feb 10 21:55:00 2015 +0100 +++ b/src/org/gege/caldavsyncadapter/caldav/entities/DavCalendar.java Tue Feb 10 22:40:00 2015 +0100 @@ -1,6 +1,6 @@ /** * Copyright (c) 2012-2013, Gerald Garcia, Timo Berger - * + * * This file is part of Andoid Caldav Sync Adapter Free. * * Andoid Caldav Sync Adapter Free is free software: you can redistribute @@ -16,27 +16,11 @@ * You should have received a copy of the GNU General Public License * along with Andoid Caldav Sync Adapter Free. * If not, see . - * + * */ package org.gege.caldavsyncadapter.caldav.entities; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; - -import javax.xml.parsers.ParserConfigurationException; - -import org.apache.http.client.ClientProtocolException; -import org.gege.caldavsyncadapter.CalendarColors; -import org.gege.caldavsyncadapter.Event; -import org.gege.caldavsyncadapter.android.entities.AndroidEvent; -import org.gege.caldavsyncadapter.caldav.CaldavFacade; -import org.gege.caldavsyncadapter.syncadapter.SyncAdapter; -import org.gege.caldavsyncadapter.syncadapter.notifications.NotificationsHelper; -import org.xml.sax.SAXException; - import android.accounts.Account; import android.content.ContentProviderClient; import android.content.ContentUris; @@ -49,618 +33,674 @@ import android.provider.CalendarContract.Events; import android.util.Log; +import org.apache.http.client.ClientProtocolException; +import org.gege.caldavsyncadapter.CalendarColors; +import org.gege.caldavsyncadapter.Event; +import org.gege.caldavsyncadapter.android.entities.AndroidEvent; +import org.gege.caldavsyncadapter.caldav.CaldavFacade; +import org.gege.caldavsyncadapter.syncadapter.SyncAdapter; +import org.gege.caldavsyncadapter.syncadapter.notifications.NotificationsHelper; +import org.xml.sax.SAXException; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.parsers.ParserConfigurationException; + public class DavCalendar { - public enum CalendarSource { - undefined, Android, CalDAV - } - - private static final String TAG = "Calendar"; - - /** - * stores the CTAG of a calendar - */ - public static String CTAG = Calendars.CAL_SYNC1; - - /** - * stores the URI of a calendar - * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname - */ - public static String URI = Calendars._SYNC_ID; - - public static String SERVERURL = Calendars.CAL_SYNC2; - - private String strCalendarColor = ""; - - private ArrayList mNotifyList = new ArrayList(); + public enum CalendarSource { + undefined, Android, CalDAV + } - /** - * the event transformed into ContentValues - */ - public ContentValues ContentValues = new ContentValues(); - - private Account mAccount = null; - private ContentProviderClient mProvider = null; - - public boolean foundServerSide = false; - public boolean foundClientSide = false; - public CalendarSource Source = CalendarSource.undefined; - - public String ServerUrl = ""; - - private ArrayList mCalendarEvents = new ArrayList(); - - private int mTagCounter = 1; - - /** - * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname - */ - public URI getURI() { - String strUri = this.getContentValueAsString(DavCalendar.URI); - URI result = null; - try { - result = new URI(strUri); - } catch (URISyntaxException e) { - e.printStackTrace(); - } - return result; - } + private static final String TAG = "Calendar"; - /** - * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname - */ - public void setURI(URI uri) { - this.setContentValueAsString(DavCalendar.URI, uri.toString()); - } + /** + * stores the CTAG of a calendar + */ + public static String CTAG = Calendars.CAL_SYNC1; - /** - * example: Cleartext Display Name - */ - public String getCalendarDisplayName() { - return this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME); - } + /** + * stores the URI of a calendar + * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname + */ + public static String URI = Calendars._SYNC_ID; - /** - * example: Cleartext Display Name - */ - public void setCalendarDisplayName(String displayName) { - this.setContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME, displayName); - } - + public static String SERVERURL = Calendars.CAL_SYNC2; - /** - * example: 1143 - */ - public void setCTag(String cTag, boolean Update) { - this.setContentValueAsString(DavCalendar.CTAG, cTag); - if (Update) { - //serverCalendar.updateAndroidCalendar(androidCalendarUri, Calendar.CTAG, serverCalendar.getcTag()); - try { - this.updateAndroidCalendar(this.getAndroidCalendarUri(), CTAG, cTag); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - } - - /** - * example: 1143 - */ - public String getcTag() { - return this.getContentValueAsString(DavCalendar.CTAG); - } - - /** - * example: #FFCCAA - */ - public void setCalendarColorAsString(String color) { - int maxlen = 6; - - this.strCalendarColor = color; - if (!color.equals("")) { - String strColor = color.replace("#", ""); - if (strColor.length() > maxlen) - strColor = strColor.substring(0, maxlen); - int intColor = Integer.parseInt(strColor, 16); - this.setContentValueAsInt(Calendars.CALENDAR_COLOR, intColor); - } - } + private String strCalendarColor = ""; - /** - * example: #FFCCAA - */ - public String getCalendarColorAsString() { - return this.strCalendarColor; - } + private ArrayList mNotifyList = new ArrayList(); - /** - * example 12345 - */ - public int getCalendarColor() { - return this.getContentValueAsInt(Calendars.CALENDAR_COLOR); - } - - /** - * example 12345 - */ - public void setCalendarColor(int color) { - this.setContentValueAsInt(Calendars.CALENDAR_COLOR, color); - } + /** + * the event transformed into ContentValues + */ + public ContentValues ContentValues = new ContentValues(); - /** - * example: - * should be: calendarname - * but is: http://caldav.example.com/calendarserver.php/calendars/username/calendarname/ - */ - public String getCalendarName() { - return this.getContentValueAsString(Calendars.NAME); - } + private Account mAccount = null; + private ContentProviderClient mProvider = null; - /** - * example: - * should be: calendarname - * but is: http://caldav.example.com/calendarserver.php/calendars/username/calendarname/ - */ - public void setCalendarName(String calendarName) { - this.setContentValueAsString(Calendars.NAME, calendarName); - } + public boolean foundServerSide = false; + public boolean foundClientSide = false; + public CalendarSource Source = CalendarSource.undefined; - /** - * example: 8 - */ - public int getAndroidCalendarId() { - return this.getContentValueAsInt(Calendars._ID); - } + public String ServerUrl = ""; - /** - * example: 8 - */ - public void setAndroidCalendarId(int androidCalendarId) { - this.setContentValueAsInt(Calendars._ID, androidCalendarId); - } + private ArrayList mCalendarEvents = new ArrayList(); - /** - * example: content://com.android.calendar/calendars/8 - */ - public Uri getAndroidCalendarUri() { - return ContentUris.withAppendedId(Calendars.CONTENT_URI, this.getAndroidCalendarId()); - } - - /** - * empty constructor - */ - public DavCalendar(CalendarSource source) { - this.Source = source; - } - - /** - * creates an new instance from a cursor - * @param cur must be a cursor from "ContentProviderClient" with Uri Calendars.CONTENT_URI - */ - public DavCalendar(Account account, ContentProviderClient provider, Cursor cur, CalendarSource source, String serverUrl) { - this.mAccount = account; - this.mProvider = provider; - this.foundClientSide = true; - this.Source = source; - this.ServerUrl = serverUrl; + private int mTagCounter = 1; - String strSyncID = cur.getString(cur.getColumnIndex(Calendars._SYNC_ID)); - String strName = cur.getString(cur.getColumnIndex(Calendars.NAME)); - String strDisplayName = cur.getString(cur.getColumnIndex(Calendars.CALENDAR_DISPLAY_NAME)); - String strCTAG = cur.getString(cur.getColumnIndex(DavCalendar.CTAG)); - String strServerUrl = cur.getString(cur.getColumnIndex(DavCalendar.SERVERURL)); - int intAndroidCalendarId = cur.getInt(cur.getColumnIndex(Calendars._ID)); + /** + * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname + */ + public URI getURI() { + String strUri = this.getContentValueAsString(DavCalendar.URI); + URI result = null; + try { + result = new URI(strUri); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + return result; + } - this.setCalendarName(strName); - this.setCalendarDisplayName(strDisplayName); - this.setCTag(strCTAG, false); - this.setAndroidCalendarId(intAndroidCalendarId); - - if (strSyncID == null) { - this.correctSyncID(strName); - strSyncID = strName; - } - if (strServerUrl == null) { - this.correctServerUrl(serverUrl); - } - URI uri = null; - try { - uri = new URI(strSyncID); - } catch (URISyntaxException e) { - e.printStackTrace(); - } - this.setURI(uri); - } - - /** - * checks a given list of android calendars for a specific android calendar. - * this calendar should be a server calendar as it is searched for. - * if the calendar is not found, it will be created. - * @param androidCalList the list of android calendars - * @param context - * @return the found android calendar or null of fails - * @throws RemoteException - */ - public Uri checkAndroidCalendarList(CalendarList androidCalList, android.content.Context context) throws RemoteException { - Uri androidCalendarUri = null; - boolean isCalendarExist = false; - - DavCalendar androidCalendar = androidCalList.getCalendarByURI(this.getURI()); - if (androidCalendar != null) { - isCalendarExist = true; - androidCalendar.foundServerSide = true; - } - + /** + * example: http://caldav.example.com/calendarserver.php/calendars/username/calendarname + */ + public void setURI(URI uri) { + this.setContentValueAsString(DavCalendar.URI, uri.toString()); + } - if (!isCalendarExist) { - DavCalendar newCal = this.createNewAndroidCalendar(this, androidCalList.getCalendarList().size(), context); - if (newCal != null) { - androidCalList.addCalendar(newCal); - androidCalendarUri = newCal.getAndroidCalendarUri(); - } - } else { - androidCalendarUri = androidCalendar.getAndroidCalendarUri(); - if (!this.getCalendarColorAsString().equals("")) { - //serverCalendar.updateCalendarColor(returnedCalendarUri, serverCalendar); - this.updateAndroidCalendar(androidCalendarUri, Calendars.CALENDAR_COLOR, this.getCalendarColor()); - } - if ((this.ContentValues.containsKey(Calendars.CALENDAR_DISPLAY_NAME)) && - (androidCalendar.ContentValues.containsKey(Calendars.CALENDAR_DISPLAY_NAME))) { - String serverDisplayName = this.ContentValues.getAsString(Calendars.CALENDAR_DISPLAY_NAME); - String clientDisplayName = androidCalendar.ContentValues.getAsString(Calendars.CALENDAR_DISPLAY_NAME); - if (!serverDisplayName.equals(clientDisplayName)) - this.updateAndroidCalendar(androidCalendarUri, Calendars.CALENDAR_DISPLAY_NAME, serverDisplayName); - } - } - - return androidCalendarUri; - } - - /** - * COMPAT: the calendar Uri was stored as calendar Name. this function updates the URI (_SYNC_ID) - * @param calendarUri the real calendarUri - * @return success of this function - */ - private boolean correctSyncID(String calendarUri) { - boolean Result = false; - Log.v(TAG, "correcting SyncID for calendar:" + this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME)); - - ContentValues mUpdateValues = new ContentValues(); - mUpdateValues.put(DavCalendar.URI, calendarUri); - - try { - mProvider.update(this.SyncAdapterCalendar(), mUpdateValues, null, null); - Result = true; - } catch (RemoteException e) { - e.printStackTrace(); - } - - return Result; - } - - /** - * COMPAT: the serverurl (CAL_SYNC2) was not sored within a calendar. this fixes it. (see #98) - * @param serverUrl the current serverurl - * @return success of this function - */ - private boolean correctServerUrl(String serverUrl) { - boolean Result = false; - Log.v(TAG, "correcting ServerUrl for calendar:" + this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME)); - - ContentValues mUpdateValues = new ContentValues(); - mUpdateValues.put(DavCalendar.SERVERURL, serverUrl); - - try { - mProvider.update(this.SyncAdapterCalendar(), mUpdateValues, null, null); - Result = true; - } catch (RemoteException e) { - e.printStackTrace(); - } - - return Result; - } - - /** - * creates a new androidCalendar - * @param serverCalendar - * @param index - * @param context - * @return the new androidCalendar or null if fails - */ - private DavCalendar createNewAndroidCalendar(DavCalendar serverCalendar, int index, android.content.Context context) { - Uri newUri = null; - DavCalendar Result = null; - - final ContentValues contentValues = new ContentValues(); - contentValues.put(DavCalendar.URI, serverCalendar.getURI().toString()); - contentValues.put(DavCalendar.SERVERURL, this.ServerUrl); + /** + * example: Cleartext Display Name + */ + public String getCalendarDisplayName() { + return this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME); + } - contentValues.put(Calendars.VISIBLE, 1); - contentValues.put(Calendars.CALENDAR_DISPLAY_NAME, serverCalendar.getCalendarDisplayName()); - contentValues.put(Calendars.ACCOUNT_NAME, mAccount.name); - contentValues.put(Calendars.ACCOUNT_TYPE, mAccount.type); - contentValues.put(Calendars.OWNER_ACCOUNT, mAccount.name); - contentValues.put(Calendars.SYNC_EVENTS, 1); - contentValues.put(Calendars.CALENDAR_ACCESS_LEVEL, Calendars.CAL_ACCESS_OWNER); - - if (!serverCalendar.getCalendarColorAsString().equals("")) { - contentValues.put(Calendars.CALENDAR_COLOR, serverCalendar.getCalendarColor()); - } else { - // find a color - //int index = mList.size(); - index = index % CalendarColors.colors.length; - contentValues.put(Calendars.CALENDAR_COLOR, CalendarColors.colors[index]); - } + /** + * example: Cleartext Display Name + */ + public void setCalendarDisplayName(String displayName) { + this.setContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME, displayName); + } - try { - newUri = mProvider.insert(asSyncAdapter(Calendars.CONTENT_URI, mAccount.name, mAccount.type), contentValues); - } catch (RemoteException e) { - e.printStackTrace(); - } - // it is possible that this calendar already exists but the provider failed to find it within isCalendarExist() - // the adapter would try to create a new calendar but the provider fails again to create a new calendar. - if (newUri != null) { - long newCalendarId = ContentUris.parseId(newUri); + /** + * example: 1143 + */ + public void setCTag(String cTag, boolean Update) { + this.setContentValueAsString(DavCalendar.CTAG, cTag); + if (Update) { + //serverCalendar.updateAndroidCalendar(androidCalendarUri, Calendar.CTAG, serverCalendar.getcTag()); + try { + this.updateAndroidCalendar(this.getAndroidCalendarUri(), CTAG, cTag); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + } - Cursor cur = null; - Uri uri = Calendars.CONTENT_URI; - String selection = "(" + Calendars._ID + " = ?)"; - String[] selectionArgs = new String[] {String.valueOf(newCalendarId)}; + /** + * example: 1143 + */ + public String getcTag() { + return this.getContentValueAsString(DavCalendar.CTAG); + } - // Submit the query and get a Cursor object back. - try { - cur = mProvider.query(uri, null, selection, selectionArgs, null); - } catch (RemoteException e) { - e.printStackTrace(); - } - - if (cur != null) { - while (cur.moveToNext()) { - Result = new DavCalendar(mAccount, mProvider, cur, this.Source, this.ServerUrl); - Result.foundServerSide = true; - } - cur.close(); - //if (Result != null) - // this.mList.add(Result); - } - Log.i(TAG, "New calendar created : URI=" + Result.getAndroidCalendarUri()); - NotificationsHelper.signalSyncErrors(context, "CalDAV Sync Adapter", "new calendar found: " + Result.getCalendarDisplayName()); - mNotifyList.add(Result.getAndroidCalendarUri()); - } - - return Result; - } - - /** - * there is no corresponding calendar on server side. time to delete this calendar on android side. - * @return - */ - public boolean deleteAndroidCalendar() { - boolean Result = false; - - String mSelectionClause = "(" + Calendars._ID + " = ?)"; - int calendarId = this.getAndroidCalendarId(); - String[] mSelectionArgs = {Long.toString(calendarId)}; - - int CountDeleted = 0; - try { - CountDeleted = mProvider.delete(this.SyncAdapter(), mSelectionClause, mSelectionArgs); - Log.i(TAG,"Calendar deleted: " + String.valueOf(calendarId)); - this.mNotifyList.add(this.getAndroidCalendarUri()); - Result = true; - } catch (RemoteException e) { - e.printStackTrace(); - } - Log.d(TAG, "Android Calendars deleted: " + Integer.toString(CountDeleted)); - - return Result; - } + /** + * example: #FFCCAA + */ + public void setCalendarColorAsString(String color) { + int maxlen = 6; - /** - * updates the android calendar - * @param calendarUri the uri of the androidCalendar - * @param target must be from android.provider.CalendarContract.Calendars - * @param value the new value for the target - * @throws RemoteException - */ - private void updateAndroidCalendar(Uri calendarUri, String target, int value) throws RemoteException { - ContentValues mUpdateValues = new ContentValues(); - mUpdateValues.put(target, value); - - mProvider.update(asSyncAdapter(calendarUri, mAccount.name, mAccount.type), mUpdateValues, null, null); - } + this.strCalendarColor = color; + if (!color.equals("")) { + String strColor = color.replace("#", ""); + if (strColor.length() > maxlen) + strColor = strColor.substring(0, maxlen); + int intColor = Integer.parseInt(strColor, 16); + this.setContentValueAsInt(Calendars.CALENDAR_COLOR, intColor); + } + } - /** - * updates the android calendar - * @param calendarUri the uri of the androidCalendar - * @param target must be from android.provider.CalendarContract.Calendars - * @param value the new value for the target - * @throws RemoteException - */ - private void updateAndroidCalendar(Uri calendarUri, String target, String value) throws RemoteException { - ContentValues mUpdateValues = new ContentValues(); - mUpdateValues.put(target, value); - - mProvider.update(asSyncAdapter(calendarUri, mAccount.name, mAccount.type), mUpdateValues, null, null); - } - - /** - * marks the android event as already handled - * @return - * @see AndroidEvent#cInternalTag - * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats) - * @throws RemoteException - */ - public boolean tagAndroidEvent(AndroidEvent androidEvent) throws RemoteException { - boolean Result = false; - - ContentValues values = new ContentValues(); - //values.put(Event.INTERNALTAG, 1); - values.put(Event.INTERNALTAG, mTagCounter); - //values.put(Event.INTERNALTAG, String.valueOf(mTagCounter)); - - int RowCount = this.mProvider.update(asSyncAdapter(androidEvent.getUri(), this.mAccount.name, this.mAccount.type), values, null, null); - //Log.v(TAG,"event tag nr: " + String.valueOf(mTagCounter)); - //Log.v(TAG,"Rows updated: " + String.valueOf(RowCount)); - - if (RowCount == 1) { - Result = true; - mTagCounter += 1; - } else { - Log.v(TAG,"EVENT NOT TAGGED!"); - } - - return Result; - } - - /** - * removes the tag of all android events - * @return - * @see AndroidEvent#cInternalTag - * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats) - * @throws RemoteException - */ - public int untagAndroidEvents() throws RemoteException { - int RowCount = 0; - int Steps = 100; - ContentValues values = new ContentValues(); - values.put(Event.INTERNALTAG, 0); + /** + * example: #FFCCAA + */ + public String getCalendarColorAsString() { + return this.strCalendarColor; + } - for (int i=1; i < this.mTagCounter; i = i + Steps) { - String mSelectionClause = "(CAST(" + Event.INTERNALTAG + " AS INT) >= ?) AND (CAST(" + Event.INTERNALTAG + " AS INT) < ?) AND (" + Events.CALENDAR_ID + " = ?)"; - String[] mSelectionArgs = {String.valueOf(i), String.valueOf(i + Steps), Long.toString(ContentUris.parseId(this.getAndroidCalendarUri()))}; - RowCount += this.mProvider.update(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), values, mSelectionClause, mSelectionArgs); - } - /*String mSelectionClause = "(" + Event.INTERNALTAG + " > ?) AND (" + Events.CALENDAR_ID + " = ?)"; - String[] mSelectionArgs = {"0", Long.toString(ContentUris.parseId(this.getAndroidCalendarUri()))}; + /** + * example 12345 + */ + public int getCalendarColor() { + return this.getContentValueAsInt(Calendars.CALENDAR_COLOR); + } + + /** + * example 12345 + */ + public void setCalendarColor(int color) { + this.setContentValueAsInt(Calendars.CALENDAR_COLOR, color); + } + + /** + * example: + * should be: calendarname + * but is: http://caldav.example.com/calendarserver.php/calendars/username/calendarname/ + */ + public String getCalendarName() { + return this.getContentValueAsString(Calendars.NAME); + } + + /** + * example: + * should be: calendarname + * but is: http://caldav.example.com/calendarserver.php/calendars/username/calendarname/ + */ + public void setCalendarName(String calendarName) { + this.setContentValueAsString(Calendars.NAME, calendarName); + } + + /** + * example: 8 + */ + public int getAndroidCalendarId() { + return this.getContentValueAsInt(Calendars._ID); + } + + /** + * example: 8 + */ + public void setAndroidCalendarId(int androidCalendarId) { + this.setContentValueAsInt(Calendars._ID, androidCalendarId); + } + + /** + * example: content://com.android.calendar/calendars/8 + */ + public Uri getAndroidCalendarUri() { + return ContentUris.withAppendedId(Calendars.CONTENT_URI, this.getAndroidCalendarId()); + } + + /** + * empty constructor + */ + public DavCalendar(CalendarSource source) { + this.Source = source; + } + + /** + * creates an new instance from a cursor + * + * @param cur must be a cursor from "ContentProviderClient" with Uri Calendars.CONTENT_URI + */ + public DavCalendar(Account account, ContentProviderClient provider, Cursor cur, CalendarSource source, String serverUrl) { + this.mAccount = account; + this.mProvider = provider; + this.foundClientSide = true; + this.Source = source; + this.ServerUrl = serverUrl; + + String strSyncID = cur.getString(cur.getColumnIndex(Calendars._SYNC_ID)); + String strName = cur.getString(cur.getColumnIndex(Calendars.NAME)); + String strDisplayName = cur.getString(cur.getColumnIndex(Calendars.CALENDAR_DISPLAY_NAME)); + String strCTAG = cur.getString(cur.getColumnIndex(DavCalendar.CTAG)); + String strServerUrl = cur.getString(cur.getColumnIndex(DavCalendar.SERVERURL)); + String strCalendarColor = cur.getString(cur.getColumnIndex(Calendars.CALENDAR_COLOR)); + int intAndroidCalendarId = cur.getInt(cur.getColumnIndex(Calendars._ID)); + + this.setCalendarName(strName); + this.setCalendarDisplayName(strDisplayName); + this.setCTag(strCTAG, false); + this.setAndroidCalendarId(intAndroidCalendarId); + this.setCalendarColor(Integer.parseInt(strCalendarColor)); + + if (strSyncID == null) { + this.correctSyncID(strName); + strSyncID = strName; + } + if (strServerUrl == null) { + this.correctServerUrl(serverUrl); + } + URI uri = null; + try { + uri = new URI(strSyncID); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + this.setURI(uri); + } + + /** + * checks a given list of android calendars for a specific android calendar. + * this calendar should be a server calendar as it is searched for. + * if the calendar is not found, it will be created. + * + * @param androidCalList the list of android calendars + * @param context + * @return the found android calendar or null of fails + * @throws RemoteException + */ + public Uri checkAndroidCalendarList(CalendarList androidCalList, android.content.Context context) throws RemoteException { + Uri androidCalendarUri = null; + boolean isCalendarExist = false; + + DavCalendar androidCalendar = androidCalList.getCalendarByURI(this.getURI()); + if (androidCalendar != null) { + isCalendarExist = true; + androidCalendar.foundServerSide = true; + } + + + if (!isCalendarExist) { + DavCalendar newCal = this.createNewAndroidCalendar(this, androidCalList.getCalendarList() + .size(), context); + if (newCal != null) { + androidCalList.addCalendar(newCal); + androidCalendarUri = newCal.getAndroidCalendarUri(); + } + } else { + androidCalendarUri = androidCalendar.getAndroidCalendarUri(); + if (!this.getCalendarColorAsString().equals("")) { + this.updateAndroidCalendar(androidCalendarUri, Calendars.CALENDAR_COLOR, getColorAsHex(this.getCalendarColorAsString())); + } + if ((this.ContentValues.containsKey(Calendars.CALENDAR_DISPLAY_NAME)) && + (androidCalendar.ContentValues.containsKey(Calendars.CALENDAR_DISPLAY_NAME))) { + String serverDisplayName = this.ContentValues.getAsString(Calendars.CALENDAR_DISPLAY_NAME); + String clientDisplayName = androidCalendar.ContentValues.getAsString(Calendars.CALENDAR_DISPLAY_NAME); + if (!serverDisplayName.equals(clientDisplayName)) + this.updateAndroidCalendar(androidCalendarUri, Calendars.CALENDAR_DISPLAY_NAME, serverDisplayName); + } + } + + return androidCalendarUri; + } + + /** + * COMPAT: the calendar Uri was stored as calendar Name. this function updates the URI (_SYNC_ID) + * + * @param calendarUri the real calendarUri + * @return success of this function + */ + private boolean correctSyncID(String calendarUri) { + boolean Result = false; + Log.v(TAG, "correcting SyncID for calendar:" + this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME)); + + ContentValues mUpdateValues = new ContentValues(); + mUpdateValues.put(DavCalendar.URI, calendarUri); + + try { + mProvider.update(this.SyncAdapterCalendar(), mUpdateValues, null, null); + Result = true; + } catch (RemoteException e) { + e.printStackTrace(); + } + + return Result; + } + + /** + * COMPAT: the serverurl (CAL_SYNC2) was not sored within a calendar. this fixes it. (see #98) + * + * @param serverUrl the current serverurl + * @return success of this function + */ + private boolean correctServerUrl(String serverUrl) { + boolean Result = false; + Log.v(TAG, "correcting ServerUrl for calendar:" + this.getContentValueAsString(Calendars.CALENDAR_DISPLAY_NAME)); + + ContentValues mUpdateValues = new ContentValues(); + mUpdateValues.put(DavCalendar.SERVERURL, serverUrl); + + try { + mProvider.update(this.SyncAdapterCalendar(), mUpdateValues, null, null); + Result = true; + } catch (RemoteException e) { + e.printStackTrace(); + } + + return Result; + } + + /** + * creates a new androidCalendar + * + * @param serverCalendar + * @param index + * @param context + * @return the new androidCalendar or null if fails + */ + private DavCalendar createNewAndroidCalendar(DavCalendar serverCalendar, int index, android.content.Context context) { + Uri newUri = null; + DavCalendar Result = null; + + final ContentValues contentValues = new ContentValues(); + contentValues.put(DavCalendar.URI, serverCalendar.getURI().toString()); + contentValues.put(DavCalendar.SERVERURL, this.ServerUrl); + + contentValues.put(Calendars.VISIBLE, 1); + contentValues.put(Calendars.CALENDAR_DISPLAY_NAME, serverCalendar.getCalendarDisplayName()); + contentValues.put(Calendars.ACCOUNT_NAME, mAccount.name); + contentValues.put(Calendars.ACCOUNT_TYPE, mAccount.type); + contentValues.put(Calendars.OWNER_ACCOUNT, mAccount.name); + contentValues.put(Calendars.SYNC_EVENTS, 1); + contentValues.put(Calendars.CALENDAR_ACCESS_LEVEL, Calendars.CAL_ACCESS_OWNER); + + String calendarColorAsString = serverCalendar.getCalendarColorAsString(); + if (!calendarColorAsString.isEmpty()) { + int color = getColorAsHex(calendarColorAsString); + contentValues.put(Calendars.CALENDAR_COLOR, color); + } else { + // find a color + //int index = mList.size(); + index = index % CalendarColors.colors.length; + contentValues.put(Calendars.CALENDAR_COLOR, CalendarColors.colors[2]); + } + + try { + newUri = mProvider.insert(asSyncAdapter(Calendars.CONTENT_URI, mAccount.name, mAccount.type), contentValues); + } catch (RemoteException e) { + e.printStackTrace(); + } + + // it is possible that this calendar already exists but the provider failed to find it within isCalendarExist() + // the adapter would try to create a new calendar but the provider fails again to create a new calendar. + if (newUri != null) { + long newCalendarId = ContentUris.parseId(newUri); + + Cursor cur = null; + Uri uri = Calendars.CONTENT_URI; + String selection = "(" + Calendars._ID + " = ?)"; + String[] selectionArgs = new String[]{String.valueOf(newCalendarId)}; + + // Submit the query and get a Cursor object back. + try { + cur = mProvider.query(uri, null, selection, selectionArgs, null); + } catch (RemoteException e) { + e.printStackTrace(); + } + + if (cur != null) { + while (cur.moveToNext()) { + Result = new DavCalendar(mAccount, mProvider, cur, this.Source, this.ServerUrl); + Result.foundServerSide = true; + } + cur.close(); + //if (Result != null) + // this.mList.add(Result); + } + Log.i(TAG, "New calendar created : URI=" + Result.getAndroidCalendarUri()); + NotificationsHelper.signalSyncErrors(context, "CalDAV Sync Adapter", "new calendar found: " + Result + .getCalendarDisplayName()); + mNotifyList.add(Result.getAndroidCalendarUri()); + } + + return Result; + } + + private int getColorAsHex(String calendarColorAsString) { + int color = 0x0000FF00; + Pattern p = Pattern.compile("#?(\\p{XDigit}{6})(\\p{XDigit}{2})?"); + Matcher m = p.matcher(calendarColorAsString); + if (m.find()) { + int color_rgb = Integer.parseInt(m.group(1), 16); + int color_alpha = m.group(2) != null ? (Integer.parseInt(m.group(2), 16) & 0xFF) : 0xFF; + color = (color_alpha << 24) | color_rgb; + } + return color; + } + + /** + * there is no corresponding calendar on server side. time to delete this calendar on android side. + * + * @return + */ + public boolean deleteAndroidCalendar() { + boolean Result = false; + + String mSelectionClause = "(" + Calendars._ID + " = ?)"; + int calendarId = this.getAndroidCalendarId(); + String[] mSelectionArgs = {Long.toString(calendarId)}; + + int CountDeleted = 0; + try { + CountDeleted = mProvider.delete(this.SyncAdapter(), mSelectionClause, mSelectionArgs); + Log.i(TAG, "Calendar deleted: " + String.valueOf(calendarId)); + this.mNotifyList.add(this.getAndroidCalendarUri()); + Result = true; + } catch (RemoteException e) { + e.printStackTrace(); + } + Log.d(TAG, "Android Calendars deleted: " + Integer.toString(CountDeleted)); + + return Result; + } + + /** + * updates the android calendar + * + * @param calendarUri the uri of the androidCalendar + * @param target must be from android.provider.CalendarContract.Calendars + * @param value the new value for the target + * @throws RemoteException + */ + private void updateAndroidCalendar(Uri calendarUri, String target, int value) throws RemoteException { + ContentValues mUpdateValues = new ContentValues(); + mUpdateValues.put(target, value); + + mProvider.update(asSyncAdapter(calendarUri, mAccount.name, mAccount.type), mUpdateValues, null, null); + } + + /** + * updates the android calendar + * + * @param calendarUri the uri of the androidCalendar + * @param target must be from android.provider.CalendarContract.Calendars + * @param value the new value for the target + * @throws RemoteException + */ + private void updateAndroidCalendar(Uri calendarUri, String target, String value) throws RemoteException { + ContentValues mUpdateValues = new ContentValues(); + mUpdateValues.put(target, value); + + mProvider.update(asSyncAdapter(calendarUri, mAccount.name, mAccount.type), mUpdateValues, null, null); + } + + /** + * marks the android event as already handled + * + * @return + * @throws RemoteException + * @see AndroidEvent#cInternalTag + * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats) + */ + public boolean tagAndroidEvent(AndroidEvent androidEvent) throws RemoteException { + boolean Result = false; + + ContentValues values = new ContentValues(); + //values.put(Event.INTERNALTAG, 1); + values.put(Event.INTERNALTAG, mTagCounter); + //values.put(Event.INTERNALTAG, String.valueOf(mTagCounter)); + + int RowCount = this.mProvider.update(asSyncAdapter(androidEvent.getUri(), this.mAccount.name, this.mAccount.type), values, null, null); + //Log.v(TAG,"event tag nr: " + String.valueOf(mTagCounter)); + //Log.v(TAG,"Rows updated: " + String.valueOf(RowCount)); + + if (RowCount == 1) { + Result = true; + mTagCounter += 1; + } else { + Log.v(TAG, "EVENT NOT TAGGED!"); + } + + return Result; + } + + /** + * removes the tag of all android events + * + * @return + * @throws RemoteException + * @see AndroidEvent#cInternalTag + * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats) + */ + public int untagAndroidEvents() throws RemoteException { + int RowCount = 0; + int Steps = 100; + ContentValues values = new ContentValues(); + values.put(Event.INTERNALTAG, 0); + + for (int i = 1; i < this.mTagCounter; i = i + Steps) { + String mSelectionClause = "(CAST(" + Event.INTERNALTAG + " AS INT) >= ?) AND (CAST(" + Event.INTERNALTAG + " AS INT) < ?) AND (" + Events.CALENDAR_ID + " = ?)"; + String[] mSelectionArgs = {String.valueOf(i), String.valueOf(i + Steps), Long.toString(ContentUris + .parseId(this.getAndroidCalendarUri()))}; + RowCount += this.mProvider.update(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), values, mSelectionClause, mSelectionArgs); + } + /*String mSelectionClause = "(" + Event.INTERNALTAG + " > ?) AND (" + Events.CALENDAR_ID + " = ?)"; + String[] mSelectionArgs = {"0", Long.toString(ContentUris.parseId(this.getAndroidCalendarUri()))}; RowCount += this.mProvider.update(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), values, mSelectionClause, mSelectionArgs);*/ - - //Log.d(TAG, "Rows reseted: " + RowCount.toString()); - return RowCount; - } - /** - * Events not being tagged are for deletion - * @return - * @see AndroidEvent#cInternalTag - * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats) - * @throws RemoteException - */ - public int deleteUntaggedEvents() throws RemoteException { - String mSelectionClause = "(" + Event.INTERNALTAG + " < ?) AND (" + Events.CALENDAR_ID + " = ?)"; - String[] mSelectionArgs = {"1", Long.toString(ContentUris.parseId(this.getAndroidCalendarUri()))}; - - int CountDeleted = this.mProvider.delete(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), mSelectionClause, mSelectionArgs); - //Log.d(TAG, "Rows deleted: " + CountDeleted.toString()); - return CountDeleted; - } - - private Uri SyncAdapterCalendar() { - return asSyncAdapter(this.getAndroidCalendarUri(), mAccount.name, mAccount.type); - } - private Uri SyncAdapter() { - return asSyncAdapter(Calendars.CONTENT_URI, mAccount.name, mAccount.type); - } - private static Uri asSyncAdapter(Uri uri, String account, String accountType) { - return uri.buildUpon() - .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true") - .appendQueryParameter(Calendars.ACCOUNT_NAME, account) - .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build(); - } - - public void setAccount(Account account) { - this.mAccount = account; - } - public void setProvider(ContentProviderClient provider) { - this.mProvider = provider; - } - - /** - * general access function to ContentValues - * @param Item the item name from Calendars.* - * @return the value for the item - */ - private String getContentValueAsString(String Item) { - String Result = ""; - if (this.ContentValues.containsKey(Item)) - Result = this.ContentValues.getAsString(Item); - return Result; - } - /** - * general access function to ContentValues - * @param Item the item name from Calendars.* - * @return the value for the item - */ - private int getContentValueAsInt(String Item) { - int Result = 0; - if (this.ContentValues.containsKey(Item)) - Result = this.ContentValues.getAsInteger(Item); - return Result; - } - - /** - * general access function to ContentValues - * @param Item the item name from Calendars.* - * @param Value the value for the item - * @return success of this function - */ - private boolean setContentValueAsString(String Item, String Value) { - boolean Result = false; - - if (this.ContentValues.containsKey(Item)) - this.ContentValues.remove(Item); - this.ContentValues.put(Item, Value); - - return Result; - } - - /** - * general access function to ContentValues - * @param Item the item name from Calendars.* - * @param Value the value for the item - * @return success of this function - */ - private boolean setContentValueAsInt(String Item, int Value) { - boolean Result = false; - - if (this.ContentValues.containsKey(Item)) - this.ContentValues.remove(Item); - this.ContentValues.put(Item, Value); - - return Result; - } - - public ArrayList getNotifyList() { - return this.mNotifyList; - } - public ArrayList getCalendarEvents() { - return this.mCalendarEvents; - } - - public boolean readCalendarEvents(CaldavFacade facade) { - boolean Result = false; - - try { - this.mCalendarEvents = facade.getCalendarEvents(this); - Result = true; - } catch (ClientProtocolException e) { - e.printStackTrace(); - Result = false; - } catch (URISyntaxException e) { - e.printStackTrace(); - Result = false; - } catch (IOException e) { - e.printStackTrace(); - Result = false; - } catch (ParserConfigurationException e) { - e.printStackTrace(); - Result = false; - } catch (SAXException e) { - e.printStackTrace(); - Result = false; - } - - return Result; - } - + //Log.d(TAG, "Rows reseted: " + RowCount.toString()); + return RowCount; + } + + /** + * Events not being tagged are for deletion + * + * @return + * @throws RemoteException + * @see AndroidEvent#cInternalTag + * @see SyncAdapter#synchroniseEvents(CaldavFacade, Account, ContentProviderClient, Uri, DavCalendar, SyncStats) + */ + public int deleteUntaggedEvents() throws RemoteException { + String mSelectionClause = "(" + Event.INTERNALTAG + " < ?) AND (" + Events.CALENDAR_ID + " = ?)"; + String[] mSelectionArgs = {"1", Long.toString(ContentUris.parseId(this.getAndroidCalendarUri()))}; + + int CountDeleted = this.mProvider.delete(asSyncAdapter(Events.CONTENT_URI, this.mAccount.name, this.mAccount.type), mSelectionClause, mSelectionArgs); + //Log.d(TAG, "Rows deleted: " + CountDeleted.toString()); + return CountDeleted; + } + + private Uri SyncAdapterCalendar() { + return asSyncAdapter(this.getAndroidCalendarUri(), mAccount.name, mAccount.type); + } + + private Uri SyncAdapter() { + return asSyncAdapter(Calendars.CONTENT_URI, mAccount.name, mAccount.type); + } + + private static Uri asSyncAdapter(Uri uri, String account, String accountType) { + return uri.buildUpon() + .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER, "true") + .appendQueryParameter(Calendars.ACCOUNT_NAME, account) + .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build(); + } + + public void setAccount(Account account) { + this.mAccount = account; + } + + public void setProvider(ContentProviderClient provider) { + this.mProvider = provider; + } + + /** + * general access function to ContentValues + * + * @param Item the item name from Calendars.* + * @return the value for the item + */ + private String getContentValueAsString(String Item) { + String Result = ""; + if (this.ContentValues.containsKey(Item)) + Result = this.ContentValues.getAsString(Item); + return Result; + } + + /** + * general access function to ContentValues + * + * @param Item the item name from Calendars.* + * @return the value for the item + */ + private int getContentValueAsInt(String Item) { + int Result = 0; + if (this.ContentValues.containsKey(Item)) + Result = this.ContentValues.getAsInteger(Item); + return Result; + } + + /** + * general access function to ContentValues + * + * @param Item the item name from Calendars.* + * @param Value the value for the item + * @return success of this function + */ + private boolean setContentValueAsString(String Item, String Value) { + boolean Result = false; + + if (this.ContentValues.containsKey(Item)) + this.ContentValues.remove(Item); + this.ContentValues.put(Item, Value); + + return Result; + } + + /** + * general access function to ContentValues + * + * @param Item the item name from Calendars.* + * @param Value the value for the item + * @return success of this function + */ + private boolean setContentValueAsInt(String Item, int Value) { + boolean Result = false; + + if (this.ContentValues.containsKey(Item)) + this.ContentValues.remove(Item); + this.ContentValues.put(Item, Value); + + return Result; + } + + public ArrayList getNotifyList() { + return this.mNotifyList; + } + + public ArrayList getCalendarEvents() { + return this.mCalendarEvents; + } + + public boolean readCalendarEvents(CaldavFacade facade) { + boolean Result = false; + + try { + this.mCalendarEvents = facade.getCalendarEvents(this); + Result = true; + } catch (ClientProtocolException e) { + e.printStackTrace(); + Result = false; + } catch (URISyntaxException e) { + e.printStackTrace(); + Result = false; + } catch (IOException e) { + e.printStackTrace(); + Result = false; + } catch (ParserConfigurationException e) { + e.printStackTrace(); + Result = false; + } catch (SAXException e) { + e.printStackTrace(); + Result = false; + } + + return Result; + } + }