X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/0348e3df377babca2852a770648d227f9091a04e..7d84fd0c9f15227bc65a2ae00a74e1cfd8f8d33b:/src/com/owncloud/android/syncadapter/FileSyncAdapter.java diff --git a/src/com/owncloud/android/syncadapter/FileSyncAdapter.java b/src/com/owncloud/android/syncadapter/FileSyncAdapter.java index ea833d49..4eafeac5 100644 --- a/src/com/owncloud/android/syncadapter/FileSyncAdapter.java +++ b/src/com/owncloud/android/syncadapter/FileSyncAdapter.java @@ -19,8 +19,10 @@ package com.owncloud.android.syncadapter; import java.io.IOException; -import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.jackrabbit.webdav.DavException; @@ -28,17 +30,15 @@ import com.owncloud.android.R; import com.owncloud.android.datamodel.DataStorageManager; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; -//<<<<<<< HEAD import com.owncloud.android.operations.RemoteOperationResult; import com.owncloud.android.operations.SynchronizeFolderOperation; import com.owncloud.android.operations.UpdateOCVersionOperation; -/*======= -import com.owncloud.android.files.services.FileDownloader; -import com.owncloud.android.files.services.FileObserverService; -import com.owncloud.android.utils.OwnCloudVersion; ->>>>>>> origin/master*/ +import com.owncloud.android.operations.RemoteOperationResult.ResultCode; +import com.owncloud.android.ui.activity.AuthenticatorActivity; +import com.owncloud.android.ui.activity.ErrorsWhileCopyingHandlerActivity; import android.accounts.Account; +import android.accounts.AccountsException; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -71,6 +71,10 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { private int mFailedResultsCounter; private RemoteOperationResult mLastFailedResult; private SyncResult mSyncResult; + private int mConflictsFound; + private int mFailsInFavouritesFound; + private Map mForgottenLocalFiles; + public FileSyncAdapter(Context context, boolean autoInitialize) { super(context, autoInitialize); @@ -88,6 +92,9 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { mIsManualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false); mFailedResultsCounter = 0; mLastFailedResult = null; + mConflictsFound = 0; + mFailsInFavouritesFound = 0; + mForgottenLocalFiles = new HashMap(); mSyncResult = syncResult; mSyncResult.fullSyncRequested = false; mSyncResult.delayUntil = 60*60*24; // sync after 24h @@ -97,7 +104,12 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { this.setStorageManager(new FileDataStorageManager(account, getContentProvider())); try { this.initClientForCurrentAccount(); - } catch (UnknownHostException e) { + } catch (IOException e) { + /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again + mSyncResult.tooManyRetries = true; + notifyFailedSynchronization(); + return; + } catch (AccountsException e) { /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again mSyncResult.tooManyRetries = true; notifyFailedSynchronization(); @@ -128,13 +140,20 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { /// notify the user about the failure of MANUAL synchronization notifyFailedSynchronization(); + + } + if (mConflictsFound > 0 || mFailsInFavouritesFound > 0) { + notifyFailsInFavourites(); + } + if (mForgottenLocalFiles.size() > 0) { + notifyForgottenLocalFiles(); + } sendStickyBroadcast(false, null, mLastFailedResult); // message to signal the end to the UI } } - - + /** * Called by system SyncManager when a synchronization is required to be cancelled. @@ -188,12 +207,19 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { // synchronized folder -> notice to UI - ALWAYS, although !result.isSuccess sendStickyBroadcast(true, remotePath, null); - if (result.isSuccess()) { + if (result.isSuccess() || result.getCode() == ResultCode.SYNC_CONFLICT) { + + if (result.getCode() == ResultCode.SYNC_CONFLICT) { + mConflictsFound += synchFolderOp.getConflictsFound(); + mFailsInFavouritesFound += synchFolderOp.getFailsInFavouritesFound(); + } + if (synchFolderOp.getForgottenLocalFiles().size() > 0) { + mForgottenLocalFiles.putAll(synchFolderOp.getForgottenLocalFiles()); + } // synchronize children folders List children = synchFolderOp.getChildren(); fetchChildren(children); // beware of the 'hidden' recursion here! -//<<<<<<< HEAD } else { if (result.getCode() == RemoteOperationResult.ResultCode.UNAUTHORIZED) { mSyncResult.stats.numAuthExceptions++; @@ -203,33 +229,6 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { } else if (result.getException() instanceof IOException) { mSyncResult.stats.numIoExceptions++; -/*======= - // insertion or update of files - List updatedFiles = new Vector(resp.getResponses().length - 1); - for (int i = 1; i < resp.getResponses().length; ++i) { - WebdavEntry we = new WebdavEntry(resp.getResponses()[i], getUri().getPath()); - OCFile file = fillOCFile(we); - file.setParentId(parentId); - if (getStorageManager().getFileByPath(file.getRemotePath()) != null && - getStorageManager().getFileByPath(file.getRemotePath()).keepInSync() && - file.getModificationTimestamp() > getStorageManager().getFileByPath(file.getRemotePath()) - .getModificationTimestamp()) { - // first disable observer so we won't get file upload right after download - Log.d(TAG, "Disabling observation of remote file" + file.getRemotePath()); - Intent intent = new Intent(getContext(), FileObserverService.class); - intent.putExtra(FileObserverService.KEY_FILE_CMD, FileObserverService.CMD_ADD_DOWNLOADING_FILE); - intent.putExtra(FileObserverService.KEY_CMD_ARG, file.getRemotePath()); - getContext().startService(intent); - intent = new Intent(this.getContext(), FileDownloader.class); - intent.putExtra(FileDownloader.EXTRA_ACCOUNT, getAccount()); - intent.putExtra(FileDownloader.EXTRA_FILE, file); - file.setKeepInSync(true); - getContext().startService(intent); - } - if (getStorageManager().getFileByPath(file.getRemotePath()) != null) - file.setKeepInSync(getStorageManager().getFileByPath(file.getRemotePath()).keepInSync()); ->>>>>>> origin/master*/ - } mFailedResultsCounter++; mLastFailedResult = result; @@ -249,6 +248,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { RemoteOperationResult.ResultCode code = failedResult.getCode(); return (code.equals(RemoteOperationResult.ResultCode.SSL_ERROR) || code.equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) || + code.equals(RemoteOperationResult.ResultCode.UNAUTHORIZED) || code.equals(RemoteOperationResult.ResultCode.BAD_OC_VERSION) || code.equals(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED)); } @@ -299,15 +299,96 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { private void notifyFailedSynchronization() { Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_ticker), System.currentTimeMillis()); notification.flags |= Notification.FLAG_AUTO_CANCEL; - // TODO put something smart in the contentIntent below + boolean needsToUpdateCredentials = (mLastFailedResult != null && mLastFailedResult.getCode() == ResultCode.UNAUTHORIZED); + // TODO put something smart in the contentIntent below for all the possible errors notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0); - notification.setLatestEventInfo(getContext().getApplicationContext(), - getContext().getString(R.string.sync_fail_ticker), - String.format(getContext().getString(R.string.sync_fail_content), getAccount().name), - notification.contentIntent); + if (needsToUpdateCredentials) { + // 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_TOKEN); + updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND); + notification.contentIntent = PendingIntent.getActivity(getContext(), (int)System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT); + notification.setLatestEventInfo(getContext().getApplicationContext(), + getContext().getString(R.string.sync_fail_ticker), + String.format(getContext().getString(R.string.sync_fail_content_unauthorized), getAccount().name), + notification.contentIntent); + Log.e(TAG, "NEEDS TO UPDATE CREDENTIALS"); + } else { + notification.setLatestEventInfo(getContext().getApplicationContext(), + getContext().getString(R.string.sync_fail_ticker), + String.format(getContext().getString(R.string.sync_fail_content), getAccount().name), + notification.contentIntent); + } ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_ticker, notification); } + + /** + * 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) { + Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_in_favourites_ticker), System.currentTimeMillis()); + notification.flags |= Notification.FLAG_AUTO_CANCEL; + // TODO put something smart in the contentIntent below + notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0); + notification.setLatestEventInfo(getContext().getApplicationContext(), + getContext().getString(R.string.sync_fail_in_favourites_ticker), + String.format(getContext().getString(R.string.sync_fail_in_favourites_content), mFailedResultsCounter + mConflictsFound, mConflictsFound), + notification.contentIntent); + ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_in_favourites_ticker, notification); + + } else { + Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_conflicts_in_favourites_ticker), System.currentTimeMillis()); + notification.flags |= Notification.FLAG_AUTO_CANCEL; + // TODO put something smart in the contentIntent below + notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0); + notification.setLatestEventInfo(getContext().getApplicationContext(), + getContext().getString(R.string.sync_conflicts_in_favourites_ticker), + String.format(getContext().getString(R.string.sync_conflicts_in_favourites_content), mConflictsFound), + notification.contentIntent); + ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_conflicts_in_favourites_ticker, notification); + } + } + + /** + * 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() { + Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_foreign_files_forgotten_ticker), System.currentTimeMillis()); + notification.flags |= Notification.FLAG_AUTO_CANCEL; + /// 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()); + ArrayList remotePaths = new ArrayList(); + ArrayList localPaths = new ArrayList(); + remotePaths.addAll(mForgottenLocalFiles.keySet()); + localPaths.addAll(mForgottenLocalFiles.values()); + explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_LOCAL_PATHS, localPaths); + explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_REMOTE_PATHS, remotePaths); + explanationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + + notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), explanationIntent, 0); + notification.setLatestEventInfo(getContext().getApplicationContext(), + getContext().getString(R.string.sync_foreign_files_forgotten_ticker), + String.format(getContext().getString(R.string.sync_foreign_files_forgotten_content), mForgottenLocalFiles.size(), getContext().getString(R.string.app_name)), + notification.contentIntent); + ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_foreign_files_forgotten_ticker, notification); + + } + + }