|
@@ -33,8 +33,6 @@ import android.content.Context;
|
|
|
import android.content.Intent;
|
|
|
import android.content.SyncResult;
|
|
|
import android.os.Bundle;
|
|
|
-import android.support.annotation.PluralsRes;
|
|
|
-import android.support.v4.app.NotificationCompat;
|
|
|
|
|
|
import com.owncloud.android.R;
|
|
|
import com.owncloud.android.authentication.AuthenticatorActivity;
|
|
@@ -59,10 +57,13 @@ import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
|
|
|
+import androidx.annotation.PluralsRes;
|
|
|
+import androidx.core.app.NotificationCompat;
|
|
|
+
|
|
|
/**
|
|
|
- * Implementation of {@link AbstractThreadedSyncAdapter} responsible for synchronizing
|
|
|
+ * Implementation of {@link AbstractThreadedSyncAdapter} responsible for synchronizing
|
|
|
* ownCloud files.
|
|
|
- *
|
|
|
+ *
|
|
|
* Performs a full synchronization of the account received in {@link #onPerformSync(Account, Bundle,
|
|
|
* String, ContentProviderClient, SyncResult)}.
|
|
|
*/
|
|
@@ -72,9 +73,9 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
|
|
|
/** Maximum number of failed folder synchronizations that are supported before finishing
|
|
|
* the synchronization operation */
|
|
|
- private static final int MAX_FAILED_RESULTS = 3;
|
|
|
-
|
|
|
-
|
|
|
+ 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() +
|
|
@@ -90,22 +91,22 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
|
|
|
/** Time stamp for the current synchronization process, used to distinguish fresh data */
|
|
|
private long mCurrentSyncTime;
|
|
|
-
|
|
|
+
|
|
|
/** Flag made 'true' when a request to cancel the synchronization is received */
|
|
|
private boolean mCancellation;
|
|
|
|
|
|
/** Counter for failed operations in the synchronization process */
|
|
|
private int mFailedResultsCounter;
|
|
|
-
|
|
|
+
|
|
|
/** Result of the last failed operation */
|
|
|
private RemoteOperationResult mLastFailedResult;
|
|
|
-
|
|
|
+
|
|
|
/** Counter of conflicts found between local and remote files */
|
|
|
private int mConflictsFound;
|
|
|
-
|
|
|
+
|
|
|
/** 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 */
|
|
|
private Map<String, String> mForgottenLocalFiles;
|
|
@@ -122,7 +123,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
super(context, autoInitialize);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* Creates a {@link FileSyncAdapter}
|
|
|
*
|
|
@@ -132,7 +133,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
super(context, autoInitialize, allowParallelSyncs);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* {@inheritDoc}
|
|
|
*/
|
|
@@ -154,7 +155,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
this.setAccount(account);
|
|
|
this.setContentProviderClient(providerClient);
|
|
|
this.setStorageManager(new FileDataStorageManager(account, providerClient));
|
|
|
-
|
|
|
+
|
|
|
try {
|
|
|
this.initClientForCurrentAccount();
|
|
|
} catch (IOException | AccountsException e) {
|
|
@@ -177,22 +178,22 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
mCurrentSyncTime = System.currentTimeMillis();
|
|
|
if (!mCancellation) {
|
|
|
synchronizeFolder(getStorageManager().getFileByPath(OCFile.ROOT_PATH));
|
|
|
-
|
|
|
+
|
|
|
} else {
|
|
|
Log_OC.d(TAG, "Leaving synchronization before synchronizing the root folder " +
|
|
|
"because cancellation request");
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
} 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)
|
|
|
mSyncResult.tooManyRetries = true;
|
|
|
-
|
|
|
+
|
|
|
/// notify the user about the failure of MANUAL synchronization
|
|
|
notifyFailedSynchronization();
|
|
|
}
|
|
@@ -205,16 +206,16 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
sendLocalBroadcast(EVENT_FULL_SYNC_END, null, mLastFailedResult); // message to signal
|
|
|
// the end to the UI
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* Called by system SyncManager when a synchronization is required to be cancelled.
|
|
|
- *
|
|
|
- * Sets the mCancellation flag to 'true'. THe synchronization will be stopped later,
|
|
|
- * before a new folder is fetched. Data of the last folder synchronized will be still
|
|
|
- * locally saved.
|
|
|
- *
|
|
|
+ *
|
|
|
+ * Sets the mCancellation flag to 'true'. THe synchronization will be stopped later,
|
|
|
+ * before a new folder is fetched. Data of the last folder synchronized will be still
|
|
|
+ * locally saved.
|
|
|
+ *
|
|
|
* See {@link #onPerformSync(Account, Bundle, String, ContentProviderClient, SyncResult)}
|
|
|
* and {@link #synchronizeFolder(OCFile)}.
|
|
|
*/
|
|
@@ -224,8 +225,8 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
mCancellation = true;
|
|
|
super.onSyncCanceled();
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* Updates the locally stored version value of the ownCloud server
|
|
|
*/
|
|
@@ -233,28 +234,28 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
UpdateOCVersionOperation update = new UpdateOCVersionOperation(getAccount(), getContext());
|
|
|
RemoteOperationResult result = update.execute(getClient());
|
|
|
if (!result.isSuccess()) {
|
|
|
- mLastFailedResult = result;
|
|
|
+ mLastFailedResult = result;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
* Synchronizes the list of files contained in a folder identified with its remote path.
|
|
|
- *
|
|
|
- * Fetches the list and properties of the files contained in the given folder, including their
|
|
|
+ *
|
|
|
+ * Fetches the list and properties of the files contained in the given folder, including their
|
|
|
* properties, and updates the local database with them.
|
|
|
- *
|
|
|
+ *
|
|
|
* Enters in the child folders to synchronize their contents also, following a recursive
|
|
|
- * depth first strategy.
|
|
|
- *
|
|
|
+ * depth first strategy.
|
|
|
+ *
|
|
|
* @param folder Folder to synchronize.
|
|
|
*/
|
|
|
private void synchronizeFolder(OCFile folder) {
|
|
|
-
|
|
|
+
|
|
|
if (mFailedResultsCounter > MAX_FAILED_RESULTS || isFinisher(mLastFailedResult)) {
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// folder synchronization
|
|
|
RefreshFolderOperation synchFolderOp = new RefreshFolderOperation( folder,
|
|
|
mCurrentSyncTime,
|
|
@@ -265,14 +266,14 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
getContext()
|
|
|
);
|
|
|
RemoteOperationResult result = synchFolderOp.execute(getClient());
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
// synchronized folder -> notice to UI - ALWAYS, although !result.isSuccess
|
|
|
sendLocalBroadcast(EVENT_FULL_SYNC_FOLDER_CONTENTS_SYNCED, folder.getRemotePath(), result);
|
|
|
-
|
|
|
+
|
|
|
// check the result of synchronizing the folder
|
|
|
if (result.isSuccess() || result.getCode() == ResultCode.SYNC_CONFLICT) {
|
|
|
-
|
|
|
+
|
|
|
if (result.getCode() == ResultCode.SYNC_CONFLICT) {
|
|
|
mConflictsFound += synchFolderOp.getConflictsFound();
|
|
|
mFailsInFavouritesFound += synchFolderOp.getFailsInKeptInSyncFound();
|
|
@@ -281,21 +282,21 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
mForgottenLocalFiles.putAll(synchFolderOp.getForgottenLocalFiles());
|
|
|
}
|
|
|
if (result.isSuccess()) {
|
|
|
- // synchronize children folders
|
|
|
+ // synchronize children folders
|
|
|
List<OCFile> children = synchFolderOp.getChildren();
|
|
|
// beware of the 'hidden' recursion here!
|
|
|
syncChildren(children);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
} else if (result.getCode() != ResultCode.FILE_NOT_FOUND) {
|
|
|
// in failures, the statistics for the global result are updated
|
|
|
if (RemoteOperationResult.ResultCode.UNAUTHORIZED.equals(result.getCode())) {
|
|
|
mSyncResult.stats.numAuthExceptions++;
|
|
|
-
|
|
|
+
|
|
|
} else if (result.getException() instanceof DavException) {
|
|
|
mSyncResult.stats.numParseExceptions++;
|
|
|
-
|
|
|
- } else if (result.getException() instanceof IOException) {
|
|
|
+
|
|
|
+ } else if (result.getException() instanceof IOException) {
|
|
|
mSyncResult.stats.numIoExceptions++;
|
|
|
}
|
|
|
mFailedResultsCounter++;
|
|
@@ -304,13 +305,13 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
} // 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
|
|
|
- *
|
|
|
+ *
|
|
|
* @param failedResult Remote operation result to check.
|
|
|
* @return 'True' if the result should immediately finish the
|
|
|
* synchronization
|
|
@@ -331,7 +332,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
*
|
|
|
* 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 syncChildren(List<OCFile> files) {
|
|
@@ -343,7 +344,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
synchronizeFolder(newFile);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (mCancellation && i <files.size()) {
|
|
|
Log_OC.d(TAG,
|
|
|
"Leaving synchronization before synchronizing " + files.get(i).getRemotePath() +
|
|
@@ -351,12 +352,12 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* 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 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 {@link SynchronizeFolderOperation},
|
|
|
* if completed; may be null.
|
|
@@ -382,10 +383,9 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
//LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
- * Notifies the user about a failed synchronization through the status notification bar
|
|
|
+ * Notifies the user about a failed synchronization through the status notification bar
|
|
|
*/
|
|
|
private void notifyFailedSynchronization() {
|
|
|
NotificationCompat.Builder notificationBuilder = createNotificationBuilder();
|
|
@@ -414,7 +414,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
.setContentTitle(i18n(R.string.sync_fail_ticker))
|
|
|
.setContentText(i18n(R.string.sync_fail_content, getAccount().name));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
showNotification(R.string.sync_fail_ticker, notificationBuilder);
|
|
|
}
|
|
|
|
|
@@ -422,14 +422,14 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
/**
|
|
|
* 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.
|
|
|
*/
|
|
|
private void notifyFailsInFavourites() {
|
|
|
if (mFailedResultsCounter > 0) {
|
|
|
NotificationCompat.Builder notificationBuilder = createNotificationBuilder();
|
|
|
notificationBuilder.setTicker(i18n(R.string.sync_fail_in_favourites_ticker));
|
|
|
-
|
|
|
+
|
|
|
// TODO put something smart in the contentIntent below
|
|
|
notificationBuilder
|
|
|
.setContentIntent(PendingIntent.getActivity(
|
|
@@ -442,12 +442,12 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
mFailedResultsCounter + mConflictsFound, mConflictsFound
|
|
|
)
|
|
|
);
|
|
|
-
|
|
|
+
|
|
|
showNotification(R.string.sync_fail_in_favourites_ticker, notificationBuilder);
|
|
|
} else {
|
|
|
NotificationCompat.Builder notificationBuilder = createNotificationBuilder();
|
|
|
notificationBuilder.setTicker(i18n(R.string.sync_conflicts_in_favourites_ticker));
|
|
|
-
|
|
|
+
|
|
|
// TODO put something smart in the contentIntent below
|
|
|
notificationBuilder
|
|
|
.setContentIntent(PendingIntent.getActivity(
|
|
@@ -455,26 +455,26 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
))
|
|
|
.setContentTitle(i18n(R.string.sync_conflicts_in_favourites_ticker))
|
|
|
.setContentText(i18n(R.string.sync_conflicts_in_favourites_ticker, mConflictsFound));
|
|
|
-
|
|
|
+
|
|
|
showNotification(R.string.sync_conflicts_in_favourites_ticker, notificationBuilder);
|
|
|
- }
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* 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 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();
|
|
|
notificationBuilder.setTicker(i18n(R.string.sync_foreign_files_forgotten_ticker));
|
|
|
-
|
|
|
+
|
|
|
/// includes a pending intent in the notification showing a more detailed explanation
|
|
|
Intent explanationIntent = new Intent(getContext(), ErrorsWhileCopyingHandlerActivity.class);
|
|
|
explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_ACCOUNT, getAccount());
|
|
@@ -483,9 +483,9 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
remotePaths.addAll(mForgottenLocalFiles.keySet());
|
|
|
localPaths.addAll(mForgottenLocalFiles.values());
|
|
|
explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_LOCAL_PATHS, localPaths);
|
|
|
- explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_REMOTE_PATHS, remotePaths);
|
|
|
+ explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_REMOTE_PATHS, remotePaths);
|
|
|
explanationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
|
-
|
|
|
+
|
|
|
notificationBuilder
|
|
|
.setContentIntent(PendingIntent.getActivity(
|
|
|
getContext(), (int) System.currentTimeMillis(), explanationIntent, 0
|
|
@@ -497,13 +497,13 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
mForgottenLocalFiles.size(),
|
|
|
i18n(R.string.app_name))
|
|
|
);
|
|
|
-
|
|
|
+
|
|
|
showNotification(R.string.sync_foreign_files_forgotten_ticker, notificationBuilder);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* Creates a notification builder with some commonly used settings
|
|
|
- *
|
|
|
+ *
|
|
|
* @return notification builder
|
|
|
*/
|
|
|
private NotificationCompat.Builder createNotificationBuilder() {
|
|
@@ -512,10 +512,10 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
notificationBuilder.setColor(ThemeUtils.primaryColor(getContext(), true));
|
|
|
return notificationBuilder;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* Builds and shows the notification
|
|
|
- *
|
|
|
+ *
|
|
|
* @param id
|
|
|
* @param builder
|
|
|
*/
|
|
@@ -531,7 +531,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
|
|
|
}
|
|
|
/**
|
|
|
* Shorthand translation
|
|
|
- *
|
|
|
+ *
|
|
|
* @param key
|
|
|
* @param args
|
|
|
* @return
|