/* * Funambol is a mobile platform developed by Funambol, Inc. * Copyright (C) 2011 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 com.funambol.client.controller; import java.util.Vector; import com.funambol.client.configuration.Configuration; import com.funambol.client.engine.SyncEngineListener; import com.funambol.client.source.AppSyncSource; import com.funambol.client.source.AppSyncSourceConfig; import com.funambol.platform.NetworkStatus; import com.funambol.sync.SyncListener; import com.funambol.util.ConnectionListener; import com.funambol.util.Log; /** * This interface includes all basic functions of a SynchronizationController * implementation that are currently shared between Android and BlackBerry * versions of SynchronizationController. */ public abstract class BasicSynchronizationController implements ConnectionListener, SyncEngineListener { private static final String TAG_LOG = "BasicSynchronizationController"; public static final String MANUAL = "manual"; public static final String SCHEDULED = "scheduled"; public static final String PUSH = "push"; protected Configuration configuration; protected NetworkStatus networkStatus; private Vector localStorageFullSources = new Vector(); private Vector serverQuotaFullSources = new Vector(); /** * Displays warnings in the proper form if the outcome of the latest sync requires so. * This method must be called when all synchronization operations are finished and the * user can be warned about problems that trigger a notification or a pop-up message * like those connected with storage limits (locally or in the cloud). */ protected void displayEndOfSyncWarnings() { if (localStorageFullSources != null && localStorageFullSources.size() > 0) { Log.debug(TAG_LOG, "Notifying storage limit warning"); displayStorageLimitWarning(localStorageFullSources); localStorageFullSources.removeAllElements(); } if (serverQuotaFullSources != null && serverQuotaFullSources.size() > 0) { Log.debug(TAG_LOG, "Notifying server quota warning"); displayServerQuotaWarning(serverQuotaFullSources); serverQuotaFullSources.removeAllElements(); } } protected void checkSourcesForStorageOrQuotaFullErrors(Vector sources) { for (int i = 0; i < sources.size(); i++) { AppSyncSource appSource = (AppSyncSource) sources.elementAt(i); switch (appSource.getConfig().getLastSyncStatus()) { case SyncListener.LOCAL_CLIENT_FULL_ERROR: // If one of the sources has risked to break the storage limit, // a warning message can have to be displayed localStorageFullSources.addElement(appSource); break; case SyncListener.SERVER_FULL_ERROR: serverQuotaFullSources.addElement(appSource); break; } } } /** * Display a background notification when max storage limit on local device * is reached. Children can override this method and implement * a foreground behavior * @param localStorageFullSources */ protected void displayStorageLimitWarning(Vector localStorageFullSources) { getBasicController().getNotificationController().showNotificationClientFull(); localStorageFullSources.removeAllElements(); } /** * Display a background notification when server quota is reached. Children * can override this method and implement a foreground behavior * @param serverQuotaFullSources */ protected void displayServerQuotaWarning(Vector serverQuotaFullSources) { getBasicController().getNotificationController().showNotificationServerFull(); serverQuotaFullSources.removeAllElements(); } protected abstract BasicController getBasicController(); /** * Applies the Bandwidth Saver by filtering out some sources or by populating * the Vector of sources that need to be synchronized only if the user accepts * to do so. * The synchronizations for sources that are filtered out are immediately set * as pending and terminated. * This method has to be called before the synchronizations actually start. * * @param syncSources all sources to be synchronized * @param sourcesWithQuestion an empty Vector * @param syncType the synchronization type * @return a sub-vector of sync sources containing only those sources that have * passed the check */ protected Vector applyBandwidthSaver(Vector syncSources, Vector sourcesWithQuestion, String syncType) { // This class cannot guarantee that these two members are not null, // therefore we check for their validity and do not filter if any of // these two is undefined if (configuration == null || networkStatus == null) { return syncSources; } if (configuration.getBandwidthSaverActivated() && !networkStatus.isWiFiConnected()) { if (Log.isLoggable(Log.TRACE)) { Log.trace(TAG_LOG, "Bandwidth saver is enabled, wifi not connected and sync type " + syncType); } // If the syncType is automatic (i.e. not manual) and WiFi is not available, // we shall skip all the sources which are to be synchronized only in WiFi if (!MANUAL.equals(syncType)) { Vector prefilteredSources = new Vector(); for (int i = 0; i < syncSources.size(); ++i) { AppSyncSource appSource = (AppSyncSource)syncSources.elementAt(i); // We need to check if the source requires to be sync'ed only in WiFi // In v9 we excluded also sync sources with online quota full, but this // behavior was modified in v10 if (appSource.getBandwidthSaverUse()) { // Skip this source because of the Bandwidth Saver. // Remember that we have a pending sync now AppSyncSourceConfig sourceConfig = appSource.getConfig(); sourceConfig.setPendingSync(syncType, sourceConfig.getSyncMode()); configuration.save(); // The sync for this source is terminated if (Log.isLoggable(Log.INFO)) { Log.info(TAG_LOG, "Ignoring sync for source: " + appSource.getName()); } sourceEnded(appSource); } else { // It's OK prefilteredSources.addElement(appSource); } } syncSources = prefilteredSources; } else { // Now check if any source to be synchronized requires user confirmation // because of the bandwidth saver for(int y = 0; y < syncSources.size(); ++y) { AppSyncSource appSource = (AppSyncSource)syncSources.elementAt(y); if(appSource.getBandwidthSaverUse()) { if (Log.isLoggable(Log.TRACE)) { Log.trace(TAG_LOG, "Found a source which requires bandwidth saver question"); } sourcesWithQuestion.addElement(appSource); } } } } return syncSources; } }