From: David A. Velasco Date: Tue, 27 May 2014 10:29:07 +0000 (+0200) Subject: Merge pull request #505 from owncloud/more_concrete_error_messages_session_expires X-Git-Tag: oc-android-1.7.0_signed~303 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/a139eca1260913a08eac5e8e167bb8b8a385e532?hp=f6fec8bfddfa288c7df584362d24c86ade8b54f9 Merge pull request #505 from owncloud/more_concrete_error_messages_session_expires More concrete error messages when session expires --- diff --git a/res/values/strings.xml b/res/values/strings.xml index 0bd9cef3..ea584f07 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -86,6 +86,7 @@ %1$s was successfully uploaded Upload failed Upload of %1$s could not be completed + Upload failed, you need to relogin Downloading … %1$d%% Downloading %2$s Download succeeded @@ -93,6 +94,7 @@ Download failed Download of %1$s could not be completed Not downloaded yet + Download failed, you need to relogin Choose account Synchronization failed Synchronization of %1$s could not be completed @@ -272,4 +274,11 @@ Copied to clipboard Critical error: can not perform operations + + An error occurred while connecting with the server. + An error occurred while waiting for the server, the operation couldn\'t have been done + An error occurred while waiting for the server, the operation couldn\'t have been done + The operation couldn\'t be completed, server is unavaliable + + diff --git a/src/com/owncloud/android/files/services/FileDownloader.java b/src/com/owncloud/android/files/services/FileDownloader.java index 461283ff..7a031359 100644 --- a/src/com/owncloud/android/files/services/FileDownloader.java +++ b/src/com/owncloud/android/files/services/FileDownloader.java @@ -44,6 +44,7 @@ import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.preview.PreviewImageActivity; import com.owncloud.android.ui.preview.PreviewImageFragment; +import com.owncloud.android.utils.ErrorMessageAdapter; import com.owncloud.android.utils.Log_OC; import com.owncloud.android.utils.NotificationBuilderWithProgressBar; @@ -461,20 +462,24 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis private void notifyDownloadResult(DownloadFileOperation download, RemoteOperationResult downloadResult) { mNotificationManager.cancel(R.string.downloader_download_in_progress_ticker); if (!downloadResult.isCancelled()) { - int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker : R.string.downloader_download_failed_ticker; - int contentId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_content : R.string.downloader_download_failed_content; - mNotificationBuilder - .setTicker(getString(tickerId)) - .setContentTitle(getString(tickerId)) - .setAutoCancel(true) - .setOngoing(false) - .setProgress(0, 0, false); + int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker : + R.string.downloader_download_failed_ticker; + boolean needsToUpdateCredentials = (downloadResult.getCode() == ResultCode.UNAUTHORIZED || - // (downloadResult.isTemporalRedirection() && downloadResult.isIdPRedirection() (downloadResult.isIdPRedirection() && mDownloadClient.getCredentials() == null)); - //&& MainApp.getAuthTokenTypeSamlSessionCookie().equals(mDownloadClient.getAuthTokenType()))); + tickerId = (needsToUpdateCredentials) ? + R.string.downloader_download_failed_credentials_error : tickerId; + + mNotificationBuilder + .setTicker(getString(tickerId)) + .setContentTitle(getString(tickerId)) + .setAutoCancel(true) + .setOngoing(false) + .setProgress(0, 0, false); + if (needsToUpdateCredentials) { + // let the user update credentials with one click Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class); updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, download.getAccount()); @@ -484,9 +489,8 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND); mNotificationBuilder .setContentIntent(PendingIntent.getActivity( - this, (int) System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT - )) - .setContentText(String.format(getString(contentId), new File(download.getSavePath()).getName())); + this, (int) System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT)); + mDownloadClient = null; // grant that future retries on the same account will get the fresh credentials } else { @@ -507,10 +511,11 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis } mNotificationBuilder .setContentIntent(PendingIntent.getActivity( - this, (int) System.currentTimeMillis(), showDetailsIntent, 0 - )) - .setContentText(String.format(getString(contentId), new File(download.getSavePath()).getName())); + this, (int) System.currentTimeMillis(), showDetailsIntent, 0)); } + + mNotificationBuilder.setContentText(ErrorMessageAdapter.getErrorCauseMessage(downloadResult, download, getResources())); + mNotificationManager.notify(tickerId, mNotificationBuilder.build()); } } diff --git a/src/com/owncloud/android/files/services/FileUploader.java b/src/com/owncloud/android/files/services/FileUploader.java index 08f9d3d4..c6408c28 100644 --- a/src/com/owncloud/android/files/services/FileUploader.java +++ b/src/com/owncloud/android/files/services/FileUploader.java @@ -54,6 +54,7 @@ import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.activity.InstantUploadActivity; import com.owncloud.android.ui.preview.PreviewImageActivity; import com.owncloud.android.ui.preview.PreviewImageFragment; +import com.owncloud.android.utils.ErrorMessageAdapter; import com.owncloud.android.utils.Log_OC; import com.owncloud.android.utils.NotificationBuilderWithProgressBar; @@ -752,10 +753,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe )) .setTicker(getString(R.string.uploader_upload_succeeded_ticker)) .setContentTitle(getString(R.string.uploader_upload_succeeded_ticker)) - .setContentText( - String.format(getString(R.string.uploader_upload_succeeded_content_single), - upload.getFileName()) - ); + .setContentText(ErrorMessageAdapter.getErrorCauseMessage(uploadResult, upload, getResources())); mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotificationBuilder.build()); // NOT // AN @@ -766,20 +764,27 @@ public class FileUploader extends Service implements OnDatatransferProgressListe } else { // / fail -> explicit failure notification - mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker); + mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker); + NotificationCompat.Builder errorBuilder = new NotificationCompat.Builder(this); - errorBuilder - .setSmallIcon(R.drawable.notification_icon) - .setTicker(getString(R.string.uploader_upload_failed_ticker)) - .setContentTitle(getString(R.string.uploader_upload_failed_ticker)) - .setAutoCancel(true); - String content = null; - boolean needsToUpdateCredentials = (uploadResult.getCode() == ResultCode.UNAUTHORIZED || - //(uploadResult.isTemporalRedirection() && uploadResult.isIdPRedirection() && + String content = null; + + // check credentials error + boolean needsToUpdateCredentials = (uploadResult.getCode() == ResultCode.UNAUTHORIZED || (uploadResult.isIdPRedirection() && mUploadClient.getCredentials() == null)); - //MainApp.getAuthTokenTypeSamlSessionCookie().equals(mUploadClient.getAuthTokenType()))); + int tickerId = (needsToUpdateCredentials) ? + R.string.uploader_upload_failed_credentials_error : R.string.uploader_upload_failed_ticker; + + errorBuilder + .setSmallIcon(R.drawable.notification_icon) + .setTicker(getString(tickerId)) + .setContentTitle(getString(tickerId)) + .setAutoCancel(true); + + content = ErrorMessageAdapter.getErrorCauseMessage(uploadResult, upload, getResources()); + if (needsToUpdateCredentials) { // let the user update credentials with one click Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class); @@ -791,23 +796,10 @@ public class FileUploader extends Service implements OnDatatransferProgressListe errorBuilder.setContentIntent(PendingIntent.getActivity( this, (int) System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT )); - content = String.format(getString(R.string.uploader_upload_failed_content_single), upload.getFileName()); + mUploadClient = null; // grant that future retries on the same account will get the fresh credentials } else { // TODO put something smart in the contentIntent below - - if (uploadResult.getCode() == ResultCode.LOCAL_STORAGE_FULL - || uploadResult.getCode() == ResultCode.LOCAL_STORAGE_NOT_COPIED) { - // TODO we need a class to provide error messages for the users - // from a RemoteOperationResult and a RemoteOperation - content = String.format(getString(R.string.error__upload__local_file_not_copied), upload.getFileName(), - getString(R.string.app_name)); - } else if (uploadResult.getCode() == ResultCode.QUOTA_EXCEEDED) { - content = getString(R.string.failed_upload_quota_exceeded_text); - } else { - content = String - .format(getString(R.string.uploader_upload_failed_content_single), upload.getFileName()); - } // we add only for instant-uploads the InstantUploadActivity and the // db entry @@ -847,7 +839,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe } errorBuilder.setContentText(content); - mNotificationManager.notify(R.string.uploader_upload_failed_ticker, errorBuilder.build()); + mNotificationManager.notify(tickerId, errorBuilder.build()); } } diff --git a/src/com/owncloud/android/ui/activity/FileActivity.java b/src/com/owncloud/android/ui/activity/FileActivity.java index f9d8bb1f..02025226 100644 --- a/src/com/owncloud/android/ui/activity/FileActivity.java +++ b/src/com/owncloud/android/ui/activity/FileActivity.java @@ -58,6 +58,7 @@ import com.owncloud.android.operations.UnshareLinkOperation; import com.owncloud.android.services.OperationsService; import com.owncloud.android.services.OperationsService.OperationsServiceBinder; import com.owncloud.android.ui.dialog.LoadingDialog; +import com.owncloud.android.utils.ErrorMessageAdapter; import com.owncloud.android.utils.Log_OC; @@ -475,14 +476,11 @@ implements OnRemoteOperationListener, ComponentsGetter { Intent sendIntent = operation.getSendIntent(); startActivity(sendIntent); - } else if (result.getCode() == ResultCode.SHARE_NOT_FOUND) { // Error --> SHARE_NOT_FOUND - Toast t = Toast.makeText(this, getString(R.string.share_link_file_no_exist), Toast.LENGTH_LONG); - t.show(); - } else { // Generic error - // Show a Message, operation finished without success - Toast t = Toast.makeText(this, getString(R.string.share_link_file_error), Toast.LENGTH_LONG); + } else { + Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), + Toast.LENGTH_LONG); t.show(); - } + } } @@ -492,15 +490,11 @@ implements OnRemoteOperationListener, ComponentsGetter { if (result.isSuccess()){ updateFileFromDB(); - } else if (result.getCode() == ResultCode.SHARE_NOT_FOUND) { // Error --> SHARE_NOT_FOUND - Toast t = Toast.makeText(this, getString(R.string.unshare_link_file_no_exist), Toast.LENGTH_LONG); - t.show(); - } else { // Generic error - // Show a Message, operation finished without success - Toast t = Toast.makeText(this, getString(R.string.unshare_link_file_error), Toast.LENGTH_LONG); + } else { + Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), + Toast.LENGTH_LONG); t.show(); - } - + } } diff --git a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java index b5e8ac0f..04d28134 100644 --- a/src/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -90,6 +90,7 @@ import com.owncloud.android.ui.preview.PreviewImageFragment; import com.owncloud.android.ui.preview.PreviewMediaFragment; import com.owncloud.android.ui.preview.PreviewVideoActivity; import com.owncloud.android.utils.DisplayUtils; +import com.owncloud.android.utils.ErrorMessageAdapter; import com.owncloud.android.utils.Log_OC; @@ -1299,9 +1300,12 @@ FileFragment.ContainerActivity, OnNavigationListener, OnSslUntrustedCertListener */ private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) { dismissLoadingDialog(); + + Toast msg = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), + Toast.LENGTH_LONG); + msg.show(); + if (result.isSuccess()) { - Toast msg = Toast.makeText(this, R.string.remove_success_msg, Toast.LENGTH_LONG); - msg.show(); OCFile removedFile = operation.getFile(); FileFragment second = getSecondFragment(); if (second != null && removedFile.equals(second.getFile())) { @@ -1316,8 +1320,6 @@ FileFragment.ContainerActivity, OnNavigationListener, OnSslUntrustedCertListener } invalidateOptionsMenu(); } else { - Toast msg = Toast.makeText(this, R.string.remove_fail_msg, Toast.LENGTH_LONG); - msg.show(); if (result.isSslRecoverableException()) { mLastSslUntrustedServerResult = result; showUntrustedCertDialog(mLastSslUntrustedServerResult); @@ -1338,17 +1340,15 @@ FileFragment.ContainerActivity, OnNavigationListener, OnSslUntrustedCertListener refreshListOfFilesFragment(); } else { dismissLoadingDialog(); - if (result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME) { - Toast.makeText(FileDisplayActivity.this, R.string.filename_forbidden_characters, Toast.LENGTH_LONG).show(); - } else { try { - Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); + Toast msg = Toast.makeText(FileDisplayActivity.this, + ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), + Toast.LENGTH_LONG); msg.show(); } catch (NotFoundException e) { Log_OC.e(TAG, "Error while trying to show fail message " , e); } - } } } @@ -1386,20 +1386,13 @@ FileFragment.ContainerActivity, OnNavigationListener, OnSslUntrustedCertListener } } else { - if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) { - Toast msg = Toast.makeText(this, R.string.rename_local_fail_msg, Toast.LENGTH_LONG); - msg.show(); - // TODO throw again the new rename dialog - } if (result.getCode().equals(ResultCode.INVALID_CHARACTER_IN_NAME)) { - Toast msg = Toast.makeText(this, R.string.filename_forbidden_characters, Toast.LENGTH_LONG); - msg.show(); - } else { - Toast msg = Toast.makeText(this, R.string.rename_server_fail_msg, Toast.LENGTH_LONG); - msg.show(); - if (result.isSslRecoverableException()) { - mLastSslUntrustedServerResult = result; - showUntrustedCertDialog(mLastSslUntrustedServerResult); - } + Toast msg = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), + Toast.LENGTH_LONG); + msg.show(); + + if (result.isSslRecoverableException()) { + mLastSslUntrustedServerResult = result; + showUntrustedCertDialog(mLastSslUntrustedServerResult); } } } @@ -1421,7 +1414,8 @@ FileFragment.ContainerActivity, OnNavigationListener, OnSslUntrustedCertListener onTransferStateChanged(syncedFile, true, true); } else { - Toast msg = Toast.makeText(this, R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); + Toast msg = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), + Toast.LENGTH_LONG); msg.show(); } } diff --git a/src/com/owncloud/android/utils/ErrorMessageAdapter.java b/src/com/owncloud/android/utils/ErrorMessageAdapter.java new file mode 100644 index 00000000..c5bda8ce --- /dev/null +++ b/src/com/owncloud/android/utils/ErrorMessageAdapter.java @@ -0,0 +1,193 @@ +/* ownCloud Android client application + * Copyright (C) 2014 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, + * as published by the Free Software Foundation. + * + * 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 General Public License + * along with this program. If not, see . + * + */ + + +package com.owncloud.android.utils; + +import java.io.File; +import java.net.SocketTimeoutException; +import org.apache.commons.httpclient.ConnectTimeoutException; +import android.content.res.Resources; + +import com.owncloud.android.R; +import com.owncloud.android.lib.common.operations.RemoteOperation; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; +import com.owncloud.android.operations.CreateFolderOperation; +import com.owncloud.android.operations.CreateShareOperation; +import com.owncloud.android.operations.DownloadFileOperation; +import com.owncloud.android.operations.RemoveFileOperation; +import com.owncloud.android.operations.RenameFileOperation; +import com.owncloud.android.operations.SynchronizeFileOperation; +import com.owncloud.android.operations.UnshareLinkOperation; +import com.owncloud.android.operations.UploadFileOperation; + +/** + * Class to choose proper error messages to show to the user depending on the results of operations, always following the same policy + * + * @author masensio + * + */ + +public class ErrorMessageAdapter { + + public ErrorMessageAdapter() { + + } + + public static String getErrorCauseMessage(RemoteOperationResult result, RemoteOperation operation, Resources res) { + + String message = null; + + if (operation instanceof UploadFileOperation) { + + if (result.isSuccess()) { + message = String.format(res.getString(R.string.uploader_upload_succeeded_content_single), + ((UploadFileOperation) operation).getFileName()); + } else { + if (result.getCode() == ResultCode.LOCAL_STORAGE_FULL + || result.getCode() == ResultCode.LOCAL_STORAGE_NOT_COPIED) { + message = String.format(res.getString(R.string.error__upload__local_file_not_copied), + ((UploadFileOperation) operation).getFileName()); + + } else if (result.getCode() == ResultCode.QUOTA_EXCEEDED) { + message = res.getString(R.string.failed_upload_quota_exceeded_text); + + } else { + message = String.format(res.getString(R.string.uploader_upload_failed_content_single), + ((UploadFileOperation) operation).getFileName()); + } + } + + } else if (operation instanceof DownloadFileOperation) { + + if (result.isSuccess()) { + message = String.format(res.getString(R.string.downloader_download_succeeded_content), + new File(((DownloadFileOperation) operation).getSavePath()).getName()); + + } else { + message = String.format(res.getString(R.string.downloader_download_failed_content), + new File(((DownloadFileOperation) operation).getSavePath()).getName()); + } + + } else if (operation instanceof RemoveFileOperation) { + if (result.isSuccess()) { + message = res.getString(R.string.remove_success_msg); + + } else { + if (isNetworkError(result.getCode())) { + message = getErrorMessage(result, res); + + } else { + message = res.getString(R.string.remove_fail_msg); + } + } + + } else if (operation instanceof RenameFileOperation) { + if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) { + message = res.getString(R.string.rename_local_fail_msg); + + } if (result.getCode().equals(ResultCode.INVALID_CHARACTER_IN_NAME)) { + message = res.getString(R.string.filename_forbidden_characters); + + } else if (isNetworkError(result.getCode())) { + message = getErrorMessage(result, res); + + } else { + message = res.getString(R.string.rename_server_fail_msg); + } + + } else if (operation instanceof SynchronizeFileOperation) { + if (!((SynchronizeFileOperation) operation).transferWasRequested()) { + message = res.getString(R.string.sync_file_nothing_to_do_msg); + } + + } else if (operation instanceof CreateFolderOperation) { + if (result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME) { + message = res.getString(R.string.filename_forbidden_characters); + + } else if (isNetworkError(result.getCode())) { + message = getErrorMessage(result, res); + + } else { + message = res.getString(R.string.create_dir_fail_msg); + } + } else if (operation instanceof CreateShareOperation) { + if (result.getCode() == ResultCode.SHARE_NOT_FOUND) { // Error --> SHARE_NOT_FOUND + message = res.getString(R.string.share_link_file_no_exist); + + } else if (isNetworkError(result.getCode())) { + message = getErrorMessage(result, res); + + } else { // Generic error + // Show a Message, operation finished without success + message = res.getString(R.string.share_link_file_error); + } + + } else if (operation instanceof UnshareLinkOperation) { + + if (result.getCode() == ResultCode.SHARE_NOT_FOUND) { // Error --> SHARE_NOT_FOUND + message = res.getString(R.string.unshare_link_file_no_exist); + + } else if (isNetworkError(result.getCode())) { + message = getErrorMessage(result, res); + + } else { // Generic error + // Show a Message, operation finished without success + message = res.getString(R.string.unshare_link_file_error); + } + } + + return message; + } + + private static String getErrorMessage(RemoteOperationResult result , Resources res) { + + String message = null; + + if (!result.isSuccess()) { + + if (result.getCode() == ResultCode.WRONG_CONNECTION) { + message = res.getString(R.string.network_error_socket_exception); + + } else if (result.getCode() == ResultCode.TIMEOUT) { + message = res.getString(R.string.network_error_socket_exception); + + if (result.getException() instanceof SocketTimeoutException) { + message = res.getString(R.string.network_error_socket_timeout_exception); + } else if(result.getException() instanceof ConnectTimeoutException) { + message = res.getString(R.string.network_error_connect_timeout_exception); + } + + } else if (result.getCode() == ResultCode.HOST_NOT_AVAILABLE) { + message = res.getString(R.string.network_host_not_available); + } + } + + return message; + } + + private static boolean isNetworkError(RemoteOperationResult.ResultCode code) { + if (code == ResultCode.WRONG_CONNECTION || + code == ResultCode.TIMEOUT || + code == ResultCode.HOST_NOT_AVAILABLE) { + return true; + } + else + return false; + } +}