/* * Funambol is a mobile platform developed by Funambol, Inc. * Copyright (C) 2010 Funambol, Inc. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License version 3 as published by * the Free Software Foundation with the addition of the following permission * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License * along with this program; if not, see http://www.gnu.org/licenses or write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA. * * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License version 3. * * In accordance with Section 7(b) of the GNU Affero General Public License * version 3, these Appropriate Legal Notices must retain the display of the * "Powered by Funambol" logo. If the display of the logo is not reasonably * feasible for technical reasons, the Appropriate Legal Notices must display * the words "Powered by Funambol". */ package de.chbosync.android.syncmlclient.source.pim.calendar; import android.accounts.Account; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.os.Build; import android.provider.CalendarContract; import android.provider.CalendarContract.Calendars; import com.funambol.sync.SyncSource; import com.funambol.util.Log; import de.chbosync.android.syncmlclient.R; import de.chbosync.android.syncmlclient.AndroidAppSyncSource; import de.chbosync.android.syncmlclient.AndroidUtils; import de.chbosync.android.syncmlclient.controller.AndroidController; public class CalendarAppSyncSource extends AndroidAppSyncSource { private static final String TAG_LOG = "CalendarAppSyncSource"; private static final int CHBOSYNC_CALENDAR_COLOR = 0xFF000066; private Context context = null; public CalendarAppSyncSource(Context context, String name, SyncSource source) { super(name, source); this.context = context; } public CalendarAppSyncSource(Context context, String name) { this(context, name, null); } @Override public boolean isWorking() { CalendarAppSyncSourceConfig config = (CalendarAppSyncSourceConfig)getConfig(); long calendarId = config.getCalendarId(); if (calendarId == -1) { return false; } else { return super.isWorking(); } } @Override public void accountCreated(String accountName, String accountType) { // The account was created, we can now create our own calendar (in case // this is needed) Log.trace(TAG_LOG, "Setting calendar to sync"); CalendarDescriptor res = createCalendar(accountName, accountType); if (res != null) { CalendarAppSyncSourceConfig config = (CalendarAppSyncSourceConfig)getConfig(); config.setCalendarId(res.getId()); config.save(); } } /** * This method can be used to create the default calendar associated to this * account. If the calendar already exists, the method simply returns a * reference to it. * * @return the calendar id */ public long createCalendar() { Account account = AndroidController.getNativeAccount(); if (account == null) { return -1; } CalendarDescriptor res = createCalendar(account.name, account.type); if (res == null) { return -1; } else { return res.getId(); } } private CalendarDescriptor createCalendar(String accountName, String accountType) { // On Android 2.2 and onward we always create the Funambol calendar to // sync. On older versions, because of a bug in Android, we try to use a // calendar that gets not removed once a google sync kicks in CalendarDescriptor res = null; if (Build.VERSION.SDK_INT >= 8 || AndroidUtils.isSimulator(context)) { Log.info(TAG_LOG, "On this version of Android, we create a separate calendar"); res = createFunambolCalendar(accountName, accountType); } return res; } /** * This class represent a calendar, with all its relevant properties */ private class CalendarDescriptor { private long id; private String displayName; public CalendarDescriptor(long id, String name) { this.id = id; this.displayName = name; } public long getId() { return id; } public String getDisplayName() { return this.displayName; } } /** * Find the default native calendar if any. * * @return a calendar descriptor if the calendar was found */ private CalendarDescriptor findNativeCalendar() { if (Log.isLoggable(Log.TRACE)) { Log.trace(TAG_LOG, "Searching for native calendars"); } ContentResolver resolver = context.getContentResolver(); Cursor dcals = resolver.query(Calendars.CONTENT_URI, null, null, null, null); if (dcals == null) { return null; } CalendarDescriptor res = null; try { if (dcals.moveToFirst()) { do { long calendarId = dcals.getLong(dcals.getColumnIndexOrThrow(Calendars._ID)); String calendarName = dcals.getString(dcals.getColumnIndexOrThrow(Calendars.CALENDAR_DISPLAY_NAME)); int syncEvents = dcals.getInt(dcals.getColumnIndexOrThrow(Calendars.SYNC_EVENTS)); String ownerAccount = dcals.getString(dcals.getColumnIndexOrThrow(Calendars.OWNER_ACCOUNT)); if (syncEvents == 0) { res = new CalendarDescriptor(calendarId, calendarName); } else { Log.debug(TAG_LOG, "Calendar found with owner account: " + ownerAccount +" id: " + calendarId + " name: " + calendarName); } if (res != null) { break; } } while(dcals.moveToNext()); } } finally { dcals.close(); } return res; } /** * Create a Funambol calendar */ private CalendarDescriptor createFunambolCalendar(String accountName, String accountType) { if (Log.isLoggable(Log.TRACE)) { Log.trace(TAG_LOG, "Creating Funambol Calendar"); } ContentResolver resolver = context.getContentResolver(); // Query all the calendars belonging to a funambol account Cursor cals = resolver.query(Calendars.CONTENT_URI, new String[]{Calendars._ID, Calendars.CALENDAR_DISPLAY_NAME}, "((" + Calendars.ACCOUNT_TYPE+"=?) AND (" + Calendars.ACCOUNT_NAME + "=?))", new String[]{accountType, accountName}, null); if (cals == null) { // No provider available for calendar. Do not even try to create a calendar Log.info(TAG_LOG, "No provider found for calendar"); return null; } CalendarDescriptor res = null; try { if(!cals.moveToFirst()) { // The funambol calendar doesn't exist -> create it if the account information is correctly loaded Log.debug(TAG_LOG, "No Funambol calendar defined, create one (" + accountName + "," + accountType); if(accountName != null && accountType != null) { String calDisplayName = context.getString(R.string.account_label); ContentValues cv = new ContentValues(); cv.put(Calendars.CALENDAR_DISPLAY_NAME, calDisplayName); cv.put(Calendars.OWNER_ACCOUNT, accountName); cv.put(Calendars.ACCOUNT_NAME, accountName); cv.put(Calendars.ACCOUNT_TYPE, accountType); cv.put(Calendars.SYNC_EVENTS, 1); // 1 == TRUE cv.put(Calendars.CALENDAR_ACCESS_LEVEL, CalendarContract.Calendars.CAL_ACCESS_OWNER); cv.put(Calendars.CALENDAR_COLOR, CHBOSYNC_CALENDAR_COLOR); Uri syncAdapterCallUri=CalendarManager.asSyncAdapter(Calendars.CONTENT_URI, accountName, accountType); Uri calUri = resolver.insert(syncAdapterCallUri, cv); long calendarId = Long.parseLong(calUri.getLastPathSegment()); res = new CalendarDescriptor(calendarId, calDisplayName); } else { Log.error(TAG_LOG, "Cannot initialize calendar since there are no accounts defined."); } } else { long calendarId = cals.getLong(cals.getColumnIndexOrThrow(Calendars._ID)); String calendarName = cals.getString(cals.getColumnIndexOrThrow(Calendars.CALENDAR_DISPLAY_NAME)); res = new CalendarDescriptor(calendarId, calendarName); if (Log.isLoggable(Log.DEBUG)) { Log.debug(TAG_LOG, "Calendar found with id: " + calendarId); } } } finally { if (cals != null) { cals.close(); } } return res; } }