-/* ownCloud Android client application
+/**
+ * ownCloud Android client application
+ *
+ * @author Bartek Przybylski
+ * @author David A. Velasco
* Copyright (C) 2011 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
+ * Copyright (C) 2015 ownCloud Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
-import com.owncloud.android.operations.SynchronizeFolderOperation;
+import com.owncloud.android.operations.RefreshFolderOperation;
import com.owncloud.android.operations.UpdateOCVersionOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.common.utils.Log_OC;
* Implementation of {@link AbstractThreadedSyncAdapter} responsible for synchronizing
* ownCloud files.
*
- * Performs a full synchronization of the account recieved in {@link #onPerformSync(Account, Bundle, String, ContentProviderClient, SyncResult)}.
- *
- * @author Bartek Przybylski
- * @author David A. Velasco
+ * Performs a full synchronization of the account received in {@link #onPerformSync(Account, Bundle,
+ * String, ContentProviderClient, SyncResult)}.
*/
public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
private final static String TAG = FileSyncAdapter.class.getSimpleName();
- /** Maximum number of failed folder synchronizations that are supported before finishing the synchronization operation */
+ /** Maximum number of failed folder synchronizations that are supported before finishing
+ * the synchronization operation */
private static final int MAX_FAILED_RESULTS = 3;
- public static final String EVENT_FULL_SYNC_START = FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_START";
- public static final String EVENT_FULL_SYNC_END = FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_END";
- public static final String EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED = FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED";
- //public static final String EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED = FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED";
-
- public static final String EXTRA_ACCOUNT_NAME = FileSyncAdapter.class.getName() + ".EXTRA_ACCOUNT_NAME";
- public static final String EXTRA_FOLDER_PATH = FileSyncAdapter.class.getName() + ".EXTRA_FOLDER_PATH";
+ public static final String EVENT_FULL_SYNC_START = FileSyncAdapter.class.getName() +
+ ".EVENT_FULL_SYNC_START";
+ public static final String EVENT_FULL_SYNC_END = FileSyncAdapter.class.getName() +
+ ".EVENT_FULL_SYNC_END";
+ public static final String EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED =
+ FileSyncAdapter.class.getName() + ".EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED";
+
+ public static final String EXTRA_ACCOUNT_NAME = FileSyncAdapter.class.getName() +
+ ".EXTRA_ACCOUNT_NAME";
+ public static final String EXTRA_FOLDER_PATH = FileSyncAdapter.class.getName() +
+ ".EXTRA_FOLDER_PATH";
public static final String EXTRA_RESULT = FileSyncAdapter.class.getName() + ".EXTRA_RESULT";
/** Flag made 'true' when a request to cancel the synchronization is received */
private boolean mCancellation;
- /** When 'true' the process was requested by the user through the user interface; when 'false', it was requested automatically by the system */
+ /** When 'true' the process was requested by the user through the user interface;
+ * when 'false', it was requested automatically by the system */
private boolean mIsManualSync;
/** Counter for failed operations in the synchronization process */
/** Counter of failed operations in synchronization of kept-in-sync files */
private int mFailsInFavouritesFound;
- /** Map of remote and local paths to files that where locally stored in a location out of the ownCloud folder and couldn't be copied automatically into it */
+ /** Map of remote and local paths to files that where locally stored in a location out
+ * of the ownCloud folder and couldn't be copied automatically into it */
private Map<String, String> mForgottenLocalFiles;
/** {@link SyncResult} instance to return to the system when the synchronization finish */
try {
this.initClientForCurrentAccount();
} catch (IOException e) {
- /// the account is unknown for the Synchronization Manager, unreachable this context, or can not be authenticated; don't try this again
+ /// the account is unknown for the Synchronization Manager, unreachable this context,
+ // or can not be authenticated; don't try this again
mSyncResult.tooManyRetries = true;
notifyFailedSynchronization();
return;
} catch (AccountsException e) {
- /// the account is unknown for the Synchronization Manager, unreachable this context, or can not be authenticated; don't try this again
+ /// the account is unknown for the Synchronization Manager, unreachable this context,
+ // or can not be authenticated; don't try this again
mSyncResult.tooManyRetries = true;
notifyFailedSynchronization();
return;
}
Log_OC.d(TAG, "Synchronization of ownCloud account " + account.name + " starting");
- sendLocalBroadcast(EVENT_FULL_SYNC_START, null, null); // message to signal the start of the synchronization to the UI
+ sendLocalBroadcast(EVENT_FULL_SYNC_START, null, null); // message to signal the start
+ // of the synchronization to the UI
try {
updateOCVersion();
synchronizeFolder(getStorageManager().getFileByPath(OCFile.ROOT_PATH));
} else {
- Log_OC.d(TAG, "Leaving synchronization before synchronizing the root folder because cancelation request");
+ Log_OC.d(TAG, "Leaving synchronization before synchronizing the root folder " +
+ "because cancelation request");
}
} finally {
- // it's important making this although very unexpected errors occur; that's the reason for the finally
+ // it's important making this although very unexpected errors occur;
+ // that's the reason for the finally
if (mFailedResultsCounter > 0 && mIsManualSync) {
/// don't let the system synchronization manager retries MANUAL synchronizations
- // (be careful: "MANUAL" currently includes the synchronization requested when a new account is created and when the user changes the current account)
+ // (be careful: "MANUAL" currently includes the synchronization requested when
+ // a new account is created and when the user changes the current account)
mSyncResult.tooManyRetries = true;
/// notify the user about the failure of MANUAL synchronization
if (mForgottenLocalFiles.size() > 0) {
notifyForgottenLocalFiles();
}
- sendLocalBroadcast(EVENT_FULL_SYNC_END, null, mLastFailedResult); // message to signal the end to the UI
+ sendLocalBroadcast(EVENT_FULL_SYNC_END, null, mLastFailedResult); // message to signal
+ // the end to the UI
}
}
* locally saved.
*
* See {@link #onPerformSync(Account, Bundle, String, ContentProviderClient, SyncResult)}
- * and {@link #synchronizeFolder(String, long)}.
+ * and {@link #synchronizeFolder(OCFile)}.
*/
@Override
public void onSyncCanceled() {
if (mFailedResultsCounter > MAX_FAILED_RESULTS || isFinisher(mLastFailedResult))
return;
- /*
- OCFile folder,
- long currentSyncTime,
- boolean updateFolderProperties,
- boolean syncFullAccount,
- DataStorageManager dataStorageManager,
- Account account,
- Context context ) {
- }
- */
// folder synchronization
- SynchronizeFolderOperation synchFolderOp = new SynchronizeFolderOperation( folder,
- mCurrentSyncTime,
- true,
- mIsShareSupported,
- true,
- getStorageManager(),
- getAccount(),
- getContext()
+ RefreshFolderOperation synchFolderOp = new RefreshFolderOperation( folder,
+ mCurrentSyncTime,
+ true,
+ mIsShareSupported,
+ false,
+ getStorageManager(),
+ getAccount(),
+ getContext()
);
RemoteOperationResult result = synchFolderOp.execute(getClient());
if (result.isSuccess()) {
// synchronize children folders
List<OCFile> children = synchFolderOp.getChildren();
- fetchChildren(folder, children, synchFolderOp.getRemoteFolderChanged()); // beware of the 'hidden' recursion here!
+ // beware of the 'hidden' recursion here!
+ syncChildren(children);
}
- } else {
+ } else if (result.getCode() != ResultCode.FILE_NOT_FOUND) {
// in failures, the statistics for the global result are updated
if ( result.getCode() == RemoteOperationResult.ResultCode.UNAUTHORIZED ||
result.isIdPRedirection()
}
mFailedResultsCounter++;
mLastFailedResult = result;
- }
+
+ } // else, ResultCode.FILE_NOT_FOUND is ignored, remote folder was
+ // removed from other thread or other client during the synchronization,
+ // before this thread fetched its contents
}
/**
- * Checks if a failed result should terminate the synchronization process immediately, according to
- * OUR OWN POLICY
+ * Checks if a failed result should terminate the synchronization process immediately,
+ * according to OUR OWN POLICY
*
* @param failedResult Remote operation result to check.
- * @return 'True' if the result should immediately finish the synchronization
+ * @return 'True' if the result should immediately finish the
+ * synchronization
*/
private boolean isFinisher(RemoteOperationResult failedResult) {
if (failedResult != null) {
/**
* Triggers the synchronization of any folder contained in the list of received files.
+ *
+ * No consideration of etag here because it MUST walk down anyway, in case that kept-in-sync files
+ * have local changes.
*
* @param files Files to recursively synchronize.
*/
- private void fetchChildren(OCFile parent, List<OCFile> files, boolean parentEtagChanged) {
+ private void syncChildren(List<OCFile> files) {
int i;
- OCFile newFile = null;
- //String etag = null;
- //boolean syncDown = false;
+ OCFile newFile;
for (i=0; i < files.size() && !mCancellation; i++) {
newFile = files.get(i);
if (newFile.isFolder()) {
- /*
- etag = newFile.getEtag();
- syncDown = (parentEtagChanged || etag == null || etag.length() == 0);
- if(syncDown) { */
- synchronizeFolder(newFile);
- //sendLocalBroadcast(EVENT_FULL_SYNC_FOLDER_SIZE_SYNCED, parent.getRemotePath(), null);
- //}
+ synchronizeFolder(newFile);
}
}
- if (mCancellation && i <files.size()) Log_OC.d(TAG, "Leaving synchronization before synchronizing " + files.get(i).getRemotePath() + " due to cancelation request");
+ if (mCancellation && i <files.size()) Log_OC.d(TAG,
+ "Leaving synchronization before synchronizing " + files.get(i).getRemotePath() +
+ " due to cancelation request");
}
/**
- * Sends a message to any application component interested in the progress of the synchronization.
+ * Sends a message to any application component interested in the progress of the
+ * synchronization.
*
* @param event Event in the process of synchronization to be notified.
* @param dirRemotePath Remote path of the folder target of the event occurred.
- * @param result Result of an individual {@ SynchronizeFolderOperation}, if completed; may be null.
+ * @param result Result of an individual {@ SynchronizeFolderOperation},
+ * if completed; may be null.
*/
- private void sendLocalBroadcast(String event, String dirRemotePath, RemoteOperationResult result) {
+ private void sendLocalBroadcast(String event, String dirRemotePath,
+ RemoteOperationResult result) {
Log_OC.d(TAG, "Send broadcast " + event);
Intent intent = new Intent(event);
intent.putExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME, getAccount().name);
// let the user update credentials with one click
Intent updateAccountCredentials = new Intent(getContext(), AuthenticatorActivity.class);
updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, getAccount());
- updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN);
+ updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION,
+ AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN);
updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);
.setTicker(i18n(R.string.sync_fail_ticker_unauthorized))
.setContentTitle(i18n(R.string.sync_fail_ticker_unauthorized))
.setContentIntent(PendingIntent.getActivity(
- getContext(), (int)System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT
+ getContext(), (int)System.currentTimeMillis(), updateAccountCredentials,
+ PendingIntent.FLAG_ONE_SHOT
))
.setContentText(i18n(R.string.sync_fail_content_unauthorized, getAccount().name));
} else {
/**
- * Notifies the user about conflicts and strange fails when trying to synchronize the contents of kept-in-sync files.
+ * Notifies the user about conflicts and strange fails when trying to synchronize the contents
+ * of kept-in-sync files.
*
* By now, we won't consider a failed synchronization.
*/
getContext(), (int) System.currentTimeMillis(), new Intent(), 0
))
.setContentTitle(i18n(R.string.sync_fail_in_favourites_ticker))
- .setContentText(i18n(R.string.sync_fail_in_favourites_content, mFailedResultsCounter + mConflictsFound, mConflictsFound));
+ .setContentText(i18n(R.string.sync_fail_in_favourites_content,
+ mFailedResultsCounter + mConflictsFound, mConflictsFound));
showNotification(R.string.sync_fail_in_favourites_ticker, notificationBuilder);
} else {
}
/**
- * Notifies the user about local copies of files out of the ownCloud local directory that were 'forgotten' because
- * copying them inside the ownCloud local directory was not possible.
+ * Notifies the user about local copies of files out of the ownCloud local directory that
+ * were 'forgotten' because copying them inside the ownCloud local directory was not possible.
*
- * We don't want links to files out of the ownCloud local directory (foreign files) anymore. It's easy to have
- * synchronization problems if a local file is linked to more than one remote file.
+ * We don't want links to files out of the ownCloud local directory (foreign files) anymore.
+ * It's easy to have synchronization problems if a local file is linked to more than one
+ * remote file.
*
- * We won't consider a synchronization as failed when foreign files can not be copied to the ownCloud local directory.
+ * We won't consider a synchronization as failed when foreign files can not be copied to
+ * the ownCloud local directory.
*/
private void notifyForgottenLocalFiles() {
NotificationCompat.Builder notificationBuilder = createNotificationBuilder();
getContext(), (int) System.currentTimeMillis(), explanationIntent, 0
))
.setContentTitle(i18n(R.string.sync_foreign_files_forgotten_ticker))
- .setContentText(i18n(R.string.sync_foreign_files_forgotten_content, mForgottenLocalFiles.size(), i18n(R.string.app_name)));
+ .setContentText(i18n(R.string.sync_foreign_files_forgotten_content,
+ mForgottenLocalFiles.size(), i18n(R.string.app_name)));
showNotification(R.string.sync_foreign_files_forgotten_ticker, notificationBuilder);
}
private NotificationCompat.Builder createNotificationBuilder() {
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(getContext());
notificationBuilder.setSmallIcon(R.drawable.notification_icon).setAutoCancel(true);
+ notificationBuilder.setColor(getContext().getResources().getColor(R.color.primary));
return notificationBuilder;
}