Эх сурвалжийг харах

Merge pull request #1198 from nextcloud/errorFeedback

Error feedback improvement
Tobias Kaminsky 7 жил өмнө
parent
commit
20048ebe54
29 өөрчлөгдсөн 698 нэмэгдсэн , 526 устгасан
  1. 1 1
      scripts/lint/lint-results.txt
  2. 52 90
      src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java
  3. 8 4
      src/main/java/com/owncloud/android/db/UploadResult.java
  4. 2 3
      src/main/java/com/owncloud/android/operations/DetectAuthenticationMethodOperation.java
  5. 3 3
      src/main/java/com/owncloud/android/operations/OAuth2GetAccessToken.java
  6. 9 9
      src/main/java/com/owncloud/android/operations/UpdateOCVersionOperation.java
  7. 8 10
      src/main/java/com/owncloud/android/ui/activity/ErrorsWhileCopyingHandlerActivity.java
  8. 12 16
      src/main/java/com/owncloud/android/ui/activity/FileActivity.java
  9. 33 42
      src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java
  10. 15 16
      src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.java
  11. 2 4
      src/main/java/com/owncloud/android/ui/activity/LogHistoryActivity.java
  12. 6 4
      src/main/java/com/owncloud/android/ui/activity/ManageSpaceActivity.java
  13. 3 4
      src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java
  14. 13 19
      src/main/java/com/owncloud/android/ui/activity/Preferences.java
  15. 14 11
      src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java
  16. 6 5
      src/main/java/com/owncloud/android/ui/activity/ShareActivity.java
  17. 2 5
      src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java
  18. 50 10
      src/main/java/com/owncloud/android/ui/adapter/ExpandableUploadListAdapter.java
  19. 5 10
      src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.java
  20. 1 1
      src/main/java/com/owncloud/android/ui/dialog/CredentialsDialogFragment.java
  21. 6 9
      src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.java
  22. 5 4
      src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java
  23. 18 16
      src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java
  24. 5 3
      src/main/java/com/owncloud/android/ui/fragment/ShareFileFragment.java
  25. 7 34
      src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java
  26. 37 0
      src/main/java/com/owncloud/android/utils/DisplayUtils.java
  27. 372 190
      src/main/java/com/owncloud/android/utils/ErrorMessageAdapter.java
  28. 0 2
      src/main/res/layout/edit_share_layout.xml
  29. 3 1
      src/main/res/values/strings.xml

+ 1 - 1
scripts/lint/lint-results.txt

@@ -1,2 +1,2 @@
 DO NOT TOUCH; GENERATED BY DRONE
-      <span class="mdl-layout-title">Lint Report: 466 warnings</span>
+      <span class="mdl-layout-title">Lint Report: 459 warnings</span>

+ 52 - 90
src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java

@@ -124,6 +124,7 @@ import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
 import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener;
 import com.owncloud.android.utils.AnalyticsUtils;
 import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.ErrorMessageAdapter;
 
 import java.net.URLDecoder;
 import java.security.cert.X509Certificate;
@@ -209,7 +210,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
     private TextView mServerStatusView;
 
     private TextWatcher mHostUrlInputWatcher;
-    private int mServerStatusText = 0, mServerStatusIcon = 0;
+    private String mServerStatusText;
+    private int mServerStatusIcon = 0;
 
     private boolean mServerIsChecked = false;
     private boolean mServerIsValid = false;
@@ -229,7 +231,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
 
     private WebView mLoginWebView;
 
-    private int mAuthStatusText = 0, mAuthStatusIcon = 0;
+    private String mAuthStatusText;
+    private int mAuthStatusIcon = 0;
 
     private String mAuthToken = "";
     private AuthenticatorAsyncTask mAsyncTask;
@@ -626,7 +629,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
                 mServerInfo.mIsSslConn = mServerInfo.mBaseUrl.startsWith(HTTPS_PROTOCOL);
             }
         } else {
-            mServerStatusText = savedInstanceState.getInt(KEY_SERVER_STATUS_TEXT);
+            mServerStatusText = savedInstanceState.getString(KEY_SERVER_STATUS_TEXT);
             mServerStatusIcon = savedInstanceState.getInt(KEY_SERVER_STATUS_ICON);
 
             mServerIsValid = savedInstanceState.getBoolean(KEY_SERVER_VALID);
@@ -691,7 +694,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
                     if (mAuthStatusIcon != 0) {
                         Log_OC.d(TAG, "onTextChanged: hiding authentication status");
                         mAuthStatusIcon = 0;
-                        mAuthStatusText = 0;
+                        mAuthStatusText = "";
                         showAuthStatus();
                     }
                 }
@@ -738,7 +741,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
             }
         } else {
             isPasswordExposed = savedInstanceState.getBoolean(KEY_PASSWORD_EXPOSED, false);
-            mAuthStatusText = savedInstanceState.getInt(KEY_AUTH_STATUS_TEXT);
+            mAuthStatusText = savedInstanceState.getString(KEY_AUTH_STATUS_TEXT);
             mAuthStatusIcon = savedInstanceState.getInt(KEY_AUTH_STATUS_ICON);
             mAuthToken = savedInstanceState.getString(KEY_AUTH_TOKEN);
         }
@@ -843,7 +846,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
 
         if (!webViewLoginMethod) {
             /// Server PRE-fragment state
-            outState.putInt(KEY_SERVER_STATUS_TEXT, mServerStatusText);
+            outState.putString(KEY_SERVER_STATUS_TEXT, mServerStatusText);
             outState.putInt(KEY_SERVER_STATUS_ICON, mServerStatusIcon);
             outState.putBoolean(KEY_SERVER_CHECKED, mServerIsChecked);
             outState.putBoolean(KEY_SERVER_VALID, mServerIsValid);
@@ -851,7 +854,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
             /// Authentication PRE-fragment state
             outState.putBoolean(KEY_PASSWORD_EXPOSED, isPasswordVisible());
             outState.putInt(KEY_AUTH_STATUS_ICON, mAuthStatusIcon);
-            outState.putInt(KEY_AUTH_STATUS_TEXT, mAuthStatusText);
+            outState.putString(KEY_AUTH_STATUS_TEXT, mAuthStatusText);
             outState.putString(KEY_AUTH_TOKEN, mAuthToken);
         }
 
@@ -1100,7 +1103,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
             }
 
             if (mHostUrlInput != null) {
-                mServerStatusText = R.string.auth_testing_connection;
+                mServerStatusText = getResources().getString(R.string.auth_testing_connection);
                 mServerStatusIcon = R.drawable.progress_small;
                 showServerStatus();
             }
@@ -1116,7 +1119,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
             }
 
         } else {
-            mServerStatusText = 0;
+            mServerStatusText = "";
             mServerStatusIcon = 0;
             if (!webViewLoginMethod) {
                 showServerStatus();
@@ -1199,7 +1202,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
                 mServerInfo.mBaseUrl == null ||
                 mServerInfo.mBaseUrl.length() == 0) {
             mServerStatusIcon = R.drawable.ic_alert;
-            mServerStatusText = R.string.auth_wtf_reenter_URL;
+            mServerStatusText = getResources().getString(R.string.auth_wtf_reenter_URL);
             showServerStatus();
             mOkButton.setEnabled(false);
             return;
@@ -1258,7 +1261,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
     private void startOauthorization() {
         // be gentle with the user
         mAuthStatusIcon = R.drawable.progress_small;
-        mAuthStatusText = R.string.oauth_login_connection;
+        mAuthStatusText = getResources().getString(R.string.oauth_login_connection);
         showAuthStatus();
 
         // GET AUTHORIZATION request
@@ -1290,7 +1293,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
     private void startSamlBasedFederatedSingleSignOnAuthorization() {
         /// be gentle with the user
         mAuthStatusIcon = R.drawable.progress_small;
-        mAuthStatusText = R.string.auth_connecting_auth_server;
+        mAuthStatusText = getResources().getString(R.string.auth_connecting_auth_server);
         showAuthStatus();
 
         /// Show SAML-based SSO web dialog
@@ -1530,74 +1533,74 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
         switch (result.getCode()) {
             case OK_SSL:
                 mServerStatusIcon = R.drawable.ic_lock_white;
-                mServerStatusText = R.string.auth_secure_connection;
+                mServerStatusText = getResources().getString(R.string.auth_secure_connection);
                 break;
 
             case OK_NO_SSL:
             case OK:
                 if (mHostUrlInput.getText().toString().trim().toLowerCase().startsWith(HTTP_PROTOCOL)) {
-                    mServerStatusText = R.string.auth_connection_established;
+                    mServerStatusText = getResources().getString(R.string.auth_connection_established);
                     mServerStatusIcon = R.drawable.ic_ok;
                 } else {
-                    mServerStatusText = R.string.auth_nossl_plain_ok_title;
+                    mServerStatusText = getResources().getString(R.string.auth_nossl_plain_ok_title);
                     mServerStatusIcon = R.drawable.ic_lock_open_white;
                 }
                 break;
 
             case NO_NETWORK_CONNECTION:
                 mServerStatusIcon = R.drawable.no_network;
-                mServerStatusText = R.string.auth_no_net_conn_title;
+                mServerStatusText = getResources().getString(R.string.auth_no_net_conn_title);
                 break;
 
             case SSL_RECOVERABLE_PEER_UNVERIFIED:
-                mServerStatusText = R.string.auth_ssl_unverified_server_title;
+                mServerStatusText = getResources().getString(R.string.auth_ssl_unverified_server_title);
                 break;
             case BAD_OC_VERSION:
-                mServerStatusText = R.string.auth_bad_oc_version_title;
+                mServerStatusText = getResources().getString(R.string.auth_bad_oc_version_title);
                 break;
             case WRONG_CONNECTION:
-                mServerStatusText = R.string.auth_wrong_connection_title;
+                mServerStatusText = getResources().getString(R.string.auth_wrong_connection_title);
                 break;
             case TIMEOUT:
-                mServerStatusText = R.string.auth_timeout_title;
+                mServerStatusText = getResources().getString(R.string.auth_timeout_title);
                 break;
             case INCORRECT_ADDRESS:
-                mServerStatusText = R.string.auth_incorrect_address_title;
+                mServerStatusText = getResources().getString(R.string.auth_incorrect_address_title);
                 break;
             case SSL_ERROR:
-                mServerStatusText = R.string.auth_ssl_general_error_title;
+                mServerStatusText = getResources().getString(R.string.auth_ssl_general_error_title);
                 break;
             case UNAUTHORIZED:
-                mServerStatusText = R.string.auth_unauthorized;
+                mServerStatusText = getResources().getString(R.string.auth_unauthorized);
                 break;
             case HOST_NOT_AVAILABLE:
-                mServerStatusText = R.string.auth_unknown_host_title;
+                mServerStatusText = getResources().getString(R.string.auth_unknown_host_title);
                 break;
             case INSTANCE_NOT_CONFIGURED:
-                mServerStatusText = R.string.auth_not_configured_title;
+                mServerStatusText = getResources().getString(R.string.auth_not_configured_title);
                 break;
             case FILE_NOT_FOUND:
-                mServerStatusText = R.string.auth_incorrect_path_title;
+                mServerStatusText = getResources().getString(R.string.auth_incorrect_path_title);
                 break;
             case OAUTH2_ERROR:
-                mServerStatusText = R.string.auth_oauth_error;
+                mServerStatusText = getResources().getString(R.string.auth_oauth_error);
                 break;
             case OAUTH2_ERROR_ACCESS_DENIED:
-                mServerStatusText = R.string.auth_oauth_error_access_denied;
+                mServerStatusText = getResources().getString(R.string.auth_oauth_error_access_denied);
                 break;
             case UNHANDLED_HTTP_CODE:
             case UNKNOWN_ERROR:
-                mServerStatusText = R.string.auth_unknown_error_title;
+                mServerStatusText = getResources().getString(R.string.auth_unknown_error_title);
                 break;
             case OK_REDIRECT_TO_NON_SECURE_CONNECTION:
                 mServerStatusIcon = R.drawable.ic_lock_open_white;
-                mServerStatusText = R.string.auth_redirect_non_secure_connection_title;
+                mServerStatusText = getResources().getString(R.string.auth_redirect_non_secure_connection_title);
                 break;
             case MAINTENANCE_MODE:
-                mServerStatusText = R.string.maintenance_mode;
+                mServerStatusText = getResources().getString(R.string.maintenance_mode);
                 break;
             default:
-                mServerStatusText = 0;
+                mServerStatusText = "";
                 mServerStatusIcon = 0;
                 break;
         }
@@ -1615,85 +1618,48 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
         switch (result.getCode()) {
             case OK_SSL:
                 mAuthStatusIcon = R.drawable.ic_lock_white;
-                mAuthStatusText = R.string.auth_secure_connection;
+                mAuthStatusText = getResources().getString(R.string.auth_secure_connection);
                 break;
 
             case OK_NO_SSL:
             case OK:
                 if (mHostUrlInput.getText().toString().trim().toLowerCase().startsWith(HTTP_PROTOCOL)) {
-                    mAuthStatusText = R.string.auth_connection_established;
+                    mAuthStatusText = getResources().getString(R.string.auth_connection_established);
                     mAuthStatusIcon = R.drawable.ic_ok;
                 } else {
-                    mAuthStatusText = R.string.auth_nossl_plain_ok_title;
+                    mAuthStatusText = getResources().getString(R.string.auth_nossl_plain_ok_title);
                     mAuthStatusIcon = R.drawable.ic_lock_open_white;
                 }
                 break;
 
             case NO_NETWORK_CONNECTION:
                 mAuthStatusIcon = R.drawable.no_network;
-                mAuthStatusText = R.string.auth_no_net_conn_title;
+                mAuthStatusText = getResources().getString(R.string.auth_no_net_conn_title);
                 break;
 
             case SSL_RECOVERABLE_PEER_UNVERIFIED:
-                mAuthStatusText = R.string.auth_ssl_unverified_server_title;
-                break;
-            case BAD_OC_VERSION:
-                mAuthStatusText = R.string.auth_bad_oc_version_title;
-                break;
-            case WRONG_CONNECTION:
-                mAuthStatusText = R.string.auth_wrong_connection_title;
+                mAuthStatusText = getResources().getString(R.string.auth_ssl_unverified_server_title);
                 break;
             case TIMEOUT:
-                mAuthStatusText = R.string.auth_timeout_title;
-                break;
-            case INCORRECT_ADDRESS:
-                mAuthStatusText = R.string.auth_incorrect_address_title;
-                break;
-            case SSL_ERROR:
-                mAuthStatusText = R.string.auth_ssl_general_error_title;
-                break;
-            case UNAUTHORIZED:
-                mAuthStatusText = R.string.auth_unauthorized;
+                mAuthStatusText = getResources().getString(R.string.auth_timeout_title);
                 break;
             case HOST_NOT_AVAILABLE:
-                mAuthStatusText = R.string.auth_unknown_host_title;
-                break;
-            case INSTANCE_NOT_CONFIGURED:
-                mAuthStatusText = R.string.auth_not_configured_title;
-                break;
-            case FILE_NOT_FOUND:
-                mAuthStatusText = R.string.auth_incorrect_path_title;
-                break;
-            case OAUTH2_ERROR:
-                mAuthStatusText = R.string.auth_oauth_error;
-                break;
-            case OAUTH2_ERROR_ACCESS_DENIED:
-                mAuthStatusText = R.string.auth_oauth_error_access_denied;
-                break;
-            case ACCOUNT_NOT_NEW:
-                mAuthStatusText = R.string.auth_account_not_new;
-                break;
-            case ACCOUNT_NOT_THE_SAME:
-                mAuthStatusText = R.string.auth_account_not_the_same;
+                mAuthStatusText = getResources().getString(R.string.auth_unknown_host_title);
                 break;
             case UNHANDLED_HTTP_CODE:
-            case UNKNOWN_ERROR:
-                mAuthStatusText = R.string.auth_unknown_error_title;
-                break;
             default:
-                mAuthStatusText = 0;
-                mAuthStatusIcon = 0;
+                mAuthStatusText = ErrorMessageAdapter.getErrorCauseMessage(result, null, getResources());
         }
     }
 
     private void updateStatusIconFailUserName(int failedStatusText){
         mAuthStatusIcon = R.drawable.ic_alert;
-        mAuthStatusText = failedStatusText;
+        mAuthStatusText = getResources().getString(failedStatusText);
     }
 
     private void updateServerStatusIconNoRegularAuth() {
         mServerStatusIcon = R.drawable.ic_alert;
-        mServerStatusText = R.string.auth_can_not_auth_against_server;
+        mServerStatusText = getResources().getString(R.string.auth_can_not_auth_against_server);
     }
 
     /**
@@ -1798,7 +1764,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
             updateServerStatusIconAndText(result);
             showServerStatus();
             mAuthStatusIcon = 0;
-            mAuthStatusText = 0;
+            mAuthStatusText = "";
             if (!webViewLoginMethod) {
                 showAuthStatus();
 
@@ -2033,7 +1999,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
      * to the last check on the ownCloud server.
      */
     private void showServerStatus() {
-        if (mServerStatusIcon == 0 && mServerStatusText == 0 || forceOldLoginMethod) {
+        if (mServerStatusIcon == 0 && "".equals(mServerStatusText) || forceOldLoginMethod) {
             mServerStatusView.setVisibility(View.INVISIBLE);
         } else {
             mServerStatusView.setText(mServerStatusText);
@@ -2048,7 +2014,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
      * to the interactions with the OAuth authorization server.
      */
     private void showAuthStatus() {
-        if (mAuthStatusIcon == 0 && mAuthStatusText == 0) {
+        if (mAuthStatusIcon == 0 && "".equals(mAuthStatusText)) {
             mAuthStatusView.setVisibility(View.INVISIBLE);
         } else {
             mAuthStatusView.setText(mAuthStatusText);
@@ -2259,7 +2225,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
     @Override
     public void onFailedSavingCertificate() {
         dismissDialog(SAML_DIALOG_TAG);
-        Toast.makeText(this, R.string.ssl_validator_not_saved, Toast.LENGTH_LONG).show();
+        DisplayUtils.showSnackMessage(this, R.string.ssl_validator_not_saved);
     }
 
     @Override
@@ -2337,20 +2303,16 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
         dialog.show(ft, CREDENTIALS_DIALOG_TAG);
 
         if (!mIsFirstAuthAttempt) {
-            Toast.makeText(
-                    getApplicationContext(),
-                    getText(R.string.saml_authentication_wrong_pass),
-                    Toast.LENGTH_LONG
-            ).show();
+            DisplayUtils.showSnackMessage(this, R.string.saml_authentication_wrong_pass);
         } else {
             mIsFirstAuthAttempt = false;
         }
     }
 
     /**
-     * For retrieving the clicking on authentication cancel button
+     * For retrieving the clicking on authentication cancel button.
      */
-    public void doNegativeAuthenticatioDialogClick() {
+    public void doNegativeAuthenticationDialogClick() {
         mIsFirstAuthAttempt = true;
     }
 }

+ 8 - 4
src/main/java/com/owncloud/android/db/UploadResult.java

@@ -37,7 +37,8 @@ public enum UploadResult {
     DELAYED_FOR_CHARGING(11),
     MAINTENANCE_MODE(12),
     LOCK_FAILED(13),
-    DELAYED_IN_POWER_SAVE_MODE(14);
+    DELAYED_IN_POWER_SAVE_MODE(14),
+    SSL_RECOVERABLE_PEER_UNVERIFIED(15);
 
     private final int value;
 
@@ -83,6 +84,8 @@ public enum UploadResult {
                 return LOCK_FAILED;
             case 14:
                 return DELAYED_IN_POWER_SAVE_MODE;
+            case 15:
+                return SSL_RECOVERABLE_PEER_UNVERIFIED;
         }
         return null;
     }
@@ -98,7 +101,6 @@ public enum UploadResult {
             case WRONG_CONNECTION:
             case INCORRECT_ADDRESS:
             case SSL_ERROR:
-            case SSL_RECOVERABLE_PEER_UNVERIFIED:
                 return NETWORK_CONNECTION;
             case ACCOUNT_EXCEPTION:
             case UNAUTHORIZED:
@@ -121,13 +123,15 @@ public enum UploadResult {
                 return DELAYED_FOR_CHARGING;
             case DELAYED_IN_POWER_SAVE_MODE:
                 return DELAYED_IN_POWER_SAVE_MODE;
+            case MAINTENANCE_MODE:
+                return MAINTENANCE_MODE;
+            case SSL_RECOVERABLE_PEER_UNVERIFIED:
+                return SSL_RECOVERABLE_PEER_UNVERIFIED;
             case UNKNOWN_ERROR:
                 if (result.getException() instanceof java.io.FileNotFoundException) {
                     return FILE_ERROR;
                 }
                 return UNKNOWN;
-            case MAINTENANCE_MODE:
-                return MAINTENANCE_MODE;
             case LOCK_FAILED:
                 return LOCK_FAILED;
             default:

+ 2 - 3
src/main/java/com/owncloud/android/operations/DetectAuthenticationMethodOperation.java

@@ -118,16 +118,15 @@ public class DetectAuthenticationMethodOperation extends RemoteOperation {
         Log_OC.d(TAG, "Authentication method found: " + authenticationMethodToString(authMethod));
         
         if (!authMethod.equals(AuthenticationMethod.UNKNOWN)) {
-            result = new RemoteOperationResult(true, result.getHttpCode(), null);
+            result = new RemoteOperationResult(true, result.getHttpCode(), result.getHttpPhrase(), null);
         }
-        ArrayList<Object> data = new ArrayList<Object>();
+        ArrayList<Object> data = new ArrayList<>();
         data.add(authMethod);
         result.setData(data);
         return result;  // same result instance, so that other errors
                         // can be handled by the caller transparently
 	}
 	
-	
 	private String authenticationMethodToString(AuthenticationMethod value) {
 	    switch (value){
 	    case NONE:

+ 3 - 3
src/main/java/com/owncloud/android/operations/OAuth2GetAccessToken.java

@@ -100,15 +100,15 @@ public class OAuth2GetAccessToken extends RemoteOperation {
                         result = new RemoteOperationResult(ResultCode.OAUTH2_ERROR);
                     
                     } else {
-                        result = new RemoteOperationResult(true, status, postMethod.getResponseHeaders());
-                        ArrayList<Object> data = new ArrayList<Object>();
+                        result = new RemoteOperationResult(true, postMethod);
+                        ArrayList<Object> data = new ArrayList<>();
                         data.add(mResultTokenMap);
                         result.setData(data);
                     }
                     
                 } else {
+                    result = new RemoteOperationResult(false, postMethod);
                     client.exhaustResponse(postMethod.getResponseBodyAsStream());
-                    result = new RemoteOperationResult(false, status, postMethod.getResponseHeaders());
                 }
             }
             

+ 9 - 9
src/main/java/com/owncloud/android/operations/UpdateOCVersionOperation.java

@@ -64,22 +64,22 @@ public class UpdateOCVersionOperation extends RemoteOperation {
         String statUrl = accountMngr.getUserData(mAccount, Constants.KEY_OC_BASE_URL);
         statUrl += AccountUtils.STATUS_PATH;
         RemoteOperationResult result = null;
-        GetMethod get = null;
+        GetMethod getMethod = null;
 
         String webDav = client.getWebdavUri().toString();
 
         try {
-            get = new GetMethod(statUrl);
-            int status = client.executeMethod(get);
+            getMethod = new GetMethod(statUrl);
+            int status = client.executeMethod(getMethod);
             if (status != HttpStatus.SC_OK) {
-                client.exhaustResponse(get.getResponseBodyAsStream());
-                result = new RemoteOperationResult(false, status, get.getResponseHeaders());
+                result = new RemoteOperationResult(false, getMethod);
+                client.exhaustResponse(getMethod.getResponseBodyAsStream());
                 
             } else {
-                String response = get.getResponseBodyAsString();
+                String response = getMethod.getResponseBodyAsString();
                 if (response != null) {
                     JSONObject json = new JSONObject(response);
-                    if (json != null && json.getString("version") != null) {
+                    if (json.getString("version") != null) {
 
                         String version = json.getString("version");
                         mOwnCloudVersion = new OwnCloudVersion(version);
@@ -112,8 +112,8 @@ public class UpdateOCVersionOperation extends RemoteOperation {
             Log_OC.e(TAG, "Check for update of ownCloud server version at " + webDav + ": " + result.getLogMessage(), e);
             
         } finally {
-            if (get != null) {
-                get.releaseConnection();
+            if (getMethod != null) {
+                getMethod.releaseConnection();
             }
         }
         return result;

+ 8 - 10
src/main/java/com/owncloud/android/ui/activity/ErrorsWhileCopyingHandlerActivity.java

@@ -26,6 +26,7 @@ import android.content.Intent;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
+import android.support.design.widget.Snackbar;
 import android.support.v4.app.DialogFragment;
 import android.support.v7.app.AppCompatActivity;
 import android.text.method.ScrollingMovementMethod;
@@ -61,8 +62,7 @@ import java.util.ArrayList;
  * 
  * Shown when the error notification summarizing the list of errors is clicked by the user.
  */
-public class ErrorsWhileCopyingHandlerActivity  extends AppCompatActivity
-        implements OnClickListener {
+public class ErrorsWhileCopyingHandlerActivity  extends AppCompatActivity implements OnClickListener {
 
     private static final String TAG = ErrorsWhileCopyingHandlerActivity.class.getSimpleName();
 
@@ -276,17 +276,15 @@ public class ErrorsWhileCopyingHandlerActivity  extends AppCompatActivity
             
             if (result) {
                 // nothing else to do in this activity
-                Toast t = Toast.makeText(ErrorsWhileCopyingHandlerActivity.this,
-                        getString(R.string.foreign_files_success), Toast.LENGTH_LONG);
-                t.show();
+                Toast.makeText(ErrorsWhileCopyingHandlerActivity.this,
+                        getString(R.string.foreign_files_success), Toast.LENGTH_LONG)
+                        .show();
                 finish();
                 
             } else {
-                Toast t = Toast.makeText(ErrorsWhileCopyingHandlerActivity.this,
-                        getString(R.string.foreign_files_fail), Toast.LENGTH_LONG);
-                t.show();
+                Snackbar.make(findViewById(android.R.id.content),R.string.foreign_files_fail,Snackbar.LENGTH_LONG)
+                        .show();
             }
         }
-    }    
-
+    }
 }

+ 12 - 16
src/main/java/com/owncloud/android/ui/activity/FileActivity.java

@@ -67,6 +67,7 @@ import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
 import com.owncloud.android.ui.dialog.LoadingDialog;
 import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
 import com.owncloud.android.ui.helpers.FileOperationsHelper;
+import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.ErrorMessageAdapter;
 
 
@@ -305,10 +306,9 @@ public abstract class FileActivity extends DrawerActivity
             requestCredentialsUpdate(this);
 
             if (result.getCode() == ResultCode.UNAUTHORIZED) {
-                Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result,
-                        operation, getResources()),
-                    Toast.LENGTH_LONG);
-                t.show();
+                DisplayUtils.showSnackMessage(
+                        this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources())
+                );
             }
 
         } else if (!result.isSuccess() && ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED.equals(result.getCode())) {
@@ -326,10 +326,9 @@ public abstract class FileActivity extends DrawerActivity
                 updateFileFromDB();
 
             } else if (result.getCode() != ResultCode.CANCELLED) {
-                Toast t = Toast.makeText(this,
-                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
-                        Toast.LENGTH_LONG);
-                t.show();
+                DisplayUtils.showSnackMessage(
+                        this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources())
+                );
             }
 
         } else if (operation instanceof SynchronizeFileOperation) {
@@ -340,10 +339,9 @@ public abstract class FileActivity extends DrawerActivity
                 updateFileFromDB();
 
             } else {
-                Toast t = Toast.makeText(this,
-                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
-                        Toast.LENGTH_LONG);
-                t.show();
+                DisplayUtils.showSnackMessage(
+                        this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources())
+                );
             }
         }
     }
@@ -379,8 +377,7 @@ public abstract class FileActivity extends DrawerActivity
             }
             OwnCloudClient client;
             OwnCloudAccount ocAccount = new OwnCloudAccount(account, context);
-            client = (OwnCloudClientManagerFactory.getDefaultSingleton().
-                    removeClientFor(ocAccount));
+            client = (OwnCloudClientManagerFactory.getDefaultSingleton().removeClientFor(ocAccount));
             if (client != null) {
                 OwnCloudCredentials cred = client.getCredentials();
                 if (cred != null) {
@@ -406,7 +403,7 @@ public abstract class FileActivity extends DrawerActivity
             startActivityForResult(updateAccountCredentials, REQUEST_CODE__UPDATE_CREDENTIALS);
 
         } catch (com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException e) {
-            Toast.makeText(context, R.string.auth_account_does_not_exist, Toast.LENGTH_SHORT).show();
+            DisplayUtils.showSnackMessage(this, R.string.auth_account_does_not_exist);
         }
 
     }
@@ -584,5 +581,4 @@ public abstract class FileActivity extends DrawerActivity
     public void onCancelCertificate() {
         // nothing to do
     }
-
 }

+ 33 - 42
src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -25,6 +25,7 @@ import android.Manifest;
 import android.accounts.Account;
 import android.accounts.AuthenticatorException;
 import android.annotation.TargetApi;
+import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -58,7 +59,6 @@ import android.view.View;
 import android.view.ViewTreeObserver;
 import android.widget.EditText;
 import android.widget.ImageView;
-import android.widget.Toast;
 
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
@@ -99,6 +99,7 @@ import com.owncloud.android.ui.preview.PreviewMediaFragment;
 import com.owncloud.android.ui.preview.PreviewTextFragment;
 import com.owncloud.android.ui.preview.PreviewVideoActivity;
 import com.owncloud.android.utils.DataHolderUtil;
+import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.ErrorMessageAdapter;
 import com.owncloud.android.utils.MimeTypeUtil;
 import com.owncloud.android.utils.PermissionUtil;
@@ -276,6 +277,10 @@ public class FileDisplayActivity extends HookActivity
         upgradeNotificationForInstantUpload();
     }
 
+    private Activity getActivity() {
+        return this;
+    }
+
     /**
      * For Android 7+.
      * Opens a pop up info for the new instant upload and disabled the old instant upload.
@@ -921,14 +926,10 @@ public class FileDisplayActivity extends HookActivity
 
         } else {
             Log_OC.d(TAG, "User clicked on 'Update' with no selection");
-            Toast t = Toast.makeText(this, getString(R.string.filedisplay_no_file_selected),
-                    Toast.LENGTH_LONG);
-            t.show();
-            return;
+            DisplayUtils.showSnackMessage(this, R.string.filedisplay_no_file_selected);
         }
     }
 
-
     private void requestUploadOfContentFromApps(Intent contentIntent, int resultCode) {
 
         ArrayList<Parcelable> streamsToUpload = new ArrayList<>();
@@ -1215,15 +1216,12 @@ public class FileDisplayActivity extends HookActivity
                                 getStorageManager().getFileByPath(getCurrentDir().getRemotePath());
 
                         if (currentDir == null) {
-                            // current folder was removed from the server 
-                            Toast.makeText(FileDisplayActivity.this,
-                                    String.format(
-                                            getString(R.string.
-                                                    sync_current_folder_was_removed),
-                                            synchFolderRemotePath),
-
-                                    Toast.LENGTH_LONG)
-                                    .show();
+                            // current folder was removed from the server
+                            DisplayUtils.showSnackMessage(
+                                    getActivity(),
+                                    R.string.sync_current_folder_was_removed,
+                                    synchFolderRemotePath
+                            );
 
                             browseToRoot();
 
@@ -1362,13 +1360,11 @@ public class FileDisplayActivity extends HookActivity
                     }
                     if (renamedInUpload) {
                         String newName = (new File(uploadedRemotePath)).getName();
-                        Toast msg = Toast.makeText(
-                                context,
-                                String.format(
-                                        getString(R.string.filedetails_renamed_in_upload_msg),
-                                        newName),
-                                Toast.LENGTH_LONG);
-                        msg.show();
+                        DisplayUtils.showSnackMessage(
+                                getActivity(),
+                                R.string.filedetails_renamed_in_upload_msg,
+                                newName
+                        );
                     }
                     if (uploadWasFine || getFile().fileExists()) {
                         ((FileDetailFragment) details).updateFileDetails(false, true);
@@ -1667,10 +1663,9 @@ public class FileDisplayActivity extends HookActivity
      */
     private void onRemoveFileOperationFinish(RemoveFileOperation operation,
                                              RemoteOperationResult result) {
-        Toast msg = Toast.makeText(this,
-                ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
-                Toast.LENGTH_LONG);
-        msg.show();
+        DisplayUtils.showSnackMessage(
+                this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources())
+        );
 
         if (result.isSuccess()) {
             OCFile removedFile = operation.getFile();
@@ -1708,10 +1703,9 @@ public class FileDisplayActivity extends HookActivity
             refreshListOfFilesFragment(false);
         } else {
             try {
-                Toast msg = Toast.makeText(FileDisplayActivity.this,
-                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
-                        Toast.LENGTH_LONG);
-                msg.show();
+                DisplayUtils.showSnackMessage(
+                        this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources())
+                );
 
             } catch (NotFoundException e) {
                 Log_OC.e(TAG, "Error while trying to show fail message ", e);
@@ -1731,10 +1725,9 @@ public class FileDisplayActivity extends HookActivity
             refreshListOfFilesFragment(false);
         } else {
             try {
-                Toast msg = Toast.makeText(FileDisplayActivity.this,
-                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
-                        Toast.LENGTH_LONG);
-                msg.show();
+                DisplayUtils.showSnackMessage(
+                        this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources())
+                );
 
             } catch (NotFoundException e) {
                 Log_OC.e(TAG, "Error while trying to show fail message ", e);
@@ -1785,10 +1778,9 @@ public class FileDisplayActivity extends HookActivity
             }
 
         } else {
-            Toast msg = Toast.makeText(this,
-                    ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
-                    Toast.LENGTH_LONG);
-            msg.show();
+            DisplayUtils.showSnackMessage(
+                    this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources())
+            );
 
             if (result.isSslRecoverableException()) {
                 mLastSslUntrustedServerResult = result;
@@ -1821,10 +1813,9 @@ public class FileDisplayActivity extends HookActivity
             refreshListOfFilesFragment(false);
         } else {
             try {
-                Toast msg = Toast.makeText(FileDisplayActivity.this,
-                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
-                        Toast.LENGTH_LONG);
-                msg.show();
+                DisplayUtils.showSnackMessage(
+                        this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources())
+                );
 
             } catch (NotFoundException e) {
                 Log_OC.e(TAG, "Error while trying to show fail message ", e);

+ 15 - 16
src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.java

@@ -21,6 +21,7 @@ package com.owncloud.android.ui.activity;
 
 import android.accounts.Account;
 import android.accounts.AuthenticatorException;
+import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -39,7 +40,6 @@ import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
-import android.widget.Toast;
 
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
@@ -55,6 +55,7 @@ import com.owncloud.android.ui.fragment.FileFragment;
 import com.owncloud.android.ui.fragment.OCFileListFragment;
 import com.owncloud.android.utils.AnalyticsUtils;
 import com.owncloud.android.utils.DataHolderUtil;
+import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.ErrorMessageAdapter;
 import com.owncloud.android.utils.ThemeUtils;
 
@@ -151,6 +152,10 @@ public class FolderPickerActivity extends FileActivity implements FileFragment.C
         }
     }
 
+    private Activity getActivity() {
+        return this;
+    }
+
     private void createFragments() {
         OCFileListFragment listOfFiles = new OCFileListFragment();
         Bundle args = new Bundle();
@@ -192,7 +197,6 @@ public class FolderPickerActivity extends FileActivity implements FileFragment.C
         Log_OC.e(TAG, "Access to unexisting list of files fragment!!");
         return null;
     }
-
     
     /**
      * {@inheritDoc}
@@ -205,7 +209,6 @@ public class FolderPickerActivity extends FileActivity implements FileFragment.C
         updateNavigationElementsInActionBar();
         // Sync Folder
         startSyncFolderOperation(directory, false);
-        
     }
 
     @Override
@@ -419,10 +422,9 @@ public class FolderPickerActivity extends FileActivity implements FileFragment.C
             refreshListOfFilesFragment(false);
         } else {
             try {
-                Toast msg = Toast.makeText(FolderPickerActivity.this, 
-                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
-                        Toast.LENGTH_LONG); 
-                msg.show();
+                DisplayUtils.showSnackMessage(
+                        this,ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources())
+                );
 
             } catch (NotFoundException e) {
                 Log_OC.e(TAG, "Error while trying to show fail message " , e);
@@ -430,8 +432,6 @@ public class FolderPickerActivity extends FileActivity implements FileFragment.C
         }
     }
     
-    
-    
     private class SyncBroadcastReceiver extends BroadcastReceiver {
 
         /**
@@ -461,13 +461,12 @@ public class FolderPickerActivity extends FileActivity implements FileFragment.C
                             getStorageManager().getFileByPath(getCurrentFolder().getRemotePath());
     
                         if (currentDir == null) {
-                            // current folder was removed from the server 
-                            Toast.makeText( FolderPickerActivity.this, 
-                                            String.format(
-                                                    getString(R.string.sync_current_folder_was_removed), 
-                                                    getCurrentFolder().getFileName()), 
-                                            Toast.LENGTH_LONG)
-                                .show();
+                            // current folder was removed from the server
+                            DisplayUtils.showSnackMessage(
+                                    getActivity(),
+                                    R.string.sync_current_folder_was_removed,
+                                    getCurrentFolder().getFileName()
+                            );
                             browseToRoot();
                             
                         } else {

+ 2 - 4
src/main/java/com/owncloud/android/ui/activity/LogHistoryActivity.java

@@ -26,6 +26,7 @@ import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
+import android.support.design.widget.Snackbar;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentTransaction;
@@ -35,7 +36,6 @@ import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.owncloud.android.R;
 import com.owncloud.android.lib.common.utils.Log_OC;
@@ -187,16 +187,14 @@ public class LogHistoryActivity extends ToolbarActivity {
         try {
             startActivity(intent);
         } catch (ActivityNotFoundException e) {
-            Toast.makeText(this, getString(R.string.log_send_no_mail_app), Toast.LENGTH_LONG).show();
+            Snackbar.make(findViewById(android.R.id.content),R.string.log_send_no_mail_app,Snackbar.LENGTH_LONG).show();
             Log_OC.i(TAG, "Could not find app for sending log history.");
         }
 
     }
 
     /**
-     *
      * Class for loading the log data async
-     *
      */
     private class LoadingLogTask extends AsyncTask<String, Void, String> {
         private final WeakReference<TextView> textViewReference;

+ 6 - 4
src/main/java/com/owncloud/android/ui/activity/ManageSpaceActivity.java

@@ -24,13 +24,13 @@ import android.content.SharedPreferences;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.preference.PreferenceManager;
+import android.support.design.widget.Snackbar;
 import android.support.v7.app.ActionBar;
 import android.support.v7.app.AppCompatActivity;
 import android.view.MenuItem;
 import android.view.View;
 import android.widget.Button;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.owncloud.android.R;
 import com.owncloud.android.lib.common.utils.Log_OC;
@@ -142,9 +142,11 @@ public class ManageSpaceActivity extends AppCompatActivity {
         protected void onPostExecute(Boolean result) {
             super.onPostExecute(result);
             if (!result) {
-                Toast.makeText(getApplicationContext(),
-                        getString(R.string.manage_space_clear_data),
-                        Toast.LENGTH_LONG).show();
+                Snackbar.make(
+                        findViewById(android.R.id.content),
+                        R.string.manage_space_clear_data,
+                        Snackbar.LENGTH_LONG
+                ).show();
             } else {
                 finish();
                 System.exit(0);

+ 3 - 4
src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java

@@ -27,6 +27,7 @@ import android.content.SharedPreferences;
 import android.graphics.PorterDuff;
 import android.os.Bundle;
 import android.preference.PreferenceManager;
+import android.support.design.widget.Snackbar;
 import android.support.v7.app.AppCompatActivity;
 import android.text.Editable;
 import android.text.TextWatcher;
@@ -37,7 +38,6 @@ import android.view.inputmethod.InputMethodManager;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.owncloud.android.R;
 import com.owncloud.android.lib.common.utils.Log_OC;
@@ -377,9 +377,8 @@ public class PassCodeActivity extends AppCompatActivity {
     private void showErrorAndRestart(int errorMessage, int headerMessage,
                                      int explanationVisibility) {
         Arrays.fill(mPassCodeDigits, null);
-        CharSequence errorSeq = getString(errorMessage);
-        Toast.makeText(this, errorSeq, Toast.LENGTH_LONG).show();
-        mPassCodeHdr.setText(headerMessage);                // TODO check if really needed
+        Snackbar.make(findViewById(android.R.id.content), getString(errorMessage), Snackbar.LENGTH_LONG).show();
+        mPassCodeHdr.setText(headerMessage);                          // TODO check if really needed
         mPassCodeHdrExplanation.setVisibility(explanationVisibility); // TODO check if really needed
         clearBoxes();
     }

+ 13 - 19
src/main/java/com/owncloud/android/ui/activity/Preferences.java

@@ -25,6 +25,7 @@ package com.owncloud.android.ui.activity;
 import android.accounts.Account;
 import android.accounts.AuthenticatorException;
 import android.accounts.OperationCanceledException;
+import android.app.Activity;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.pm.PackageInfo;
@@ -54,7 +55,6 @@ import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.Toast;
 
 import com.owncloud.android.BuildConfig;
 import com.owncloud.android.MainApp;
@@ -70,6 +70,7 @@ import com.owncloud.android.lib.common.OwnCloudAccount;
 import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.utils.AnalyticsUtils;
+import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.ThemeUtils;
 
 import java.io.IOException;
@@ -257,6 +258,7 @@ public class Preferences extends PreferenceActivity
         if (fPrint != null) {
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                 if (FingerprintActivity.isFingerprintCapable(MainApp.getAppContext()) && fPrintEnabled) {
+                    final Activity activity = this;
                     fPrint.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
                         @Override
                         public boolean onPreferenceChange(Preference preference, Object newValue) {
@@ -272,11 +274,7 @@ public class Preferences extends PreferenceActivity
                                     return true;
                                 } else {
                                     if (incoming) {
-                                        Toast.makeText(
-                                                MainApp.getAppContext(),
-                                                R.string.prefs_fingerprint_notsetup,
-                                                Toast.LENGTH_LONG)
-                                                .show();
+                                        DisplayUtils.showSnackMessage(activity, R.string.prefs_fingerprint_notsetup);
                                         fPrint.setChecked(false);
                                     }
                                     SharedPreferences appPrefs =
@@ -359,6 +357,7 @@ public class Preferences extends PreferenceActivity
         Preference pCalendarContacts = findPreference("calendar_contacts");
         if (pCalendarContacts != null) {
             if (calendarContactsEnabled) {
+                final Activity activity = this;
                 pCalendarContacts.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                     @Override
                     public boolean onPreferenceClick(Preference preference) {
@@ -366,11 +365,10 @@ public class Preferences extends PreferenceActivity
                             launchDavDroidLogin();
                         } catch (Throwable t) {
                             Log_OC.e(TAG, "Base Uri for account could not be resolved to call DAVdroid!", t);
-                            Toast.makeText(
-                                    MainApp.getAppContext(),
-                                    R.string.prefs_calendar_contacts_address_resolve_error,
-                                    Toast.LENGTH_SHORT)
-                                    .show();
+                            DisplayUtils.showSnackMessage(
+                                    activity,
+                                    R.string.prefs_calendar_contacts_address_resolve_error
+                            );
                         }
                         return true;
                     }
@@ -675,11 +673,7 @@ public class Preferences extends PreferenceActivity
                         Uri.parse("https://f-droid.org/repository/browse/?fdid=at.bitfire.davdroid"));
                 startActivity(downloadIntent);
 
-                Toast.makeText(
-                        MainApp.getAppContext(),
-                        R.string.prefs_calendar_contacts_no_store_error,
-                        Toast.LENGTH_SHORT)
-                        .show();
+                DisplayUtils.showSnackMessage(this, R.string.prefs_calendar_contacts_no_store_error);
             }
         }
     }
@@ -751,7 +745,7 @@ public class Preferences extends PreferenceActivity
                 }
                 appPrefs.putBoolean(PassCodeActivity.PREFERENCE_SET_PASSCODE, true);
                 appPrefs.apply();
-                Toast.makeText(this, R.string.pass_code_stored, Toast.LENGTH_LONG).show();
+                DisplayUtils.showSnackMessage(this, R.string.pass_code_stored);
             }
         } else if (requestCode == ACTION_CONFIRM_PASSCODE && resultCode == RESULT_OK) {
             if (data.getBooleanExtra(PassCodeActivity.KEY_CHECK_RESULT, false)) {
@@ -761,10 +755,10 @@ public class Preferences extends PreferenceActivity
                 appPrefs.putBoolean(PassCodeActivity.PREFERENCE_SET_PASSCODE, false);
                 appPrefs.apply();
 
-                Toast.makeText(this, R.string.pass_code_removed, Toast.LENGTH_LONG).show();
+                DisplayUtils.showSnackMessage(this, R.string.pass_code_removed);
             }
         } else if (requestCode == ACTION_REQUEST_CODE_DAVDROID_SETUP && resultCode == RESULT_OK) {
-            Toast.makeText(this, R.string.prefs_calendar_contacts_sync_setup_successful, Toast.LENGTH_LONG).show();
+            DisplayUtils.showSnackMessage(this, R.string.prefs_calendar_contacts_sync_setup_successful);
         }
     }
 

+ 14 - 11
src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java

@@ -26,6 +26,7 @@ package com.owncloud.android.ui.activity;
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AuthenticatorException;
+import android.app.Activity;
 import android.app.Dialog;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -70,7 +71,6 @@ import android.widget.ListView;
 import android.widget.ProgressBar;
 import android.widget.Spinner;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
@@ -94,6 +94,7 @@ import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
 import com.owncloud.android.ui.fragment.TaskRetainerFragment;
 import com.owncloud.android.ui.helpers.UriUploader;
 import com.owncloud.android.utils.DataHolderUtil;
+import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.ErrorMessageAdapter;
 import com.owncloud.android.utils.FileStorageUtils;
 import com.owncloud.android.utils.ThemeUtils;
@@ -212,6 +213,10 @@ public class ReceiveExternalFilesActivity extends FileActivity
         dialog.show(getSupportFragmentManager(), null);
     }
 
+    private Activity getActivity() {
+        return this;
+    }
+
     @Override
     protected void onAccountSet(boolean stateWasRecovered) {
         super.onAccountSet(mAccountWasRestored);
@@ -976,10 +981,9 @@ public class ReceiveExternalFilesActivity extends FileActivity
             populateDirectoryList();
         } else {
             try {
-                Toast msg = Toast.makeText(this,
-                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
-                        Toast.LENGTH_LONG);
-                msg.show();
+                DisplayUtils.showSnackMessage(
+                        this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources())
+                );
 
             } catch (NotFoundException e) {
                 Log_OC.e(TAG, "Error while trying to show fail message ", e);
@@ -1108,12 +1112,11 @@ public class ReceiveExternalFilesActivity extends FileActivity
 
                         if (currentDir == null) {
                             // current folder was removed from the server
-                            Toast.makeText(context,
-                                    String.format(
-                                            getString(R.string.sync_current_folder_was_removed),
-                                            getCurrentFolder().getFileName()),
-                                    Toast.LENGTH_LONG)
-                                    .show();
+                            DisplayUtils.showSnackMessage(
+                                    getActivity(),
+                                    R.string.sync_current_folder_was_removed,
+                                    getCurrentFolder().getFileName()
+                            );
                             browseToRoot();
 
                         } else {

+ 6 - 5
src/main/java/com/owncloud/android/ui/activity/ShareActivity.java

@@ -25,10 +25,10 @@ import android.app.SearchManager;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
+import android.support.design.widget.Snackbar;
 import android.support.v4.app.DialogFragment;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentTransaction;
-import android.widget.Toast;
 
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
@@ -354,10 +354,11 @@ public class ShareActivity extends FileActivity implements ShareFragmentListener
                 }
 
             } else {
-                Toast t = Toast.makeText(this,
-                    ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
-                    Toast.LENGTH_LONG);
-                t.show();
+                Snackbar.make(
+                        findViewById(android.R.id.content),
+                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+                        Snackbar.LENGTH_LONG
+                ).show();
             }
         }
     }

+ 2 - 5
src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java

@@ -40,7 +40,6 @@ import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
-import android.widget.Toast;
 
 import com.evernote.android.job.JobRequest;
 import com.evernote.android.job.util.support.PersistableBundleCompat;
@@ -168,8 +167,7 @@ public class UploadListActivity extends FileActivity implements UploadListFragme
         /// TODO is this path still active?
         File f = new File(file.getLocalPath());
         if(!f.exists()) {
-            Toast.makeText(this, "Cannot open. Local file does not exist.",
-                    Toast.LENGTH_SHORT).show();
+            DisplayUtils.showSnackMessage(this, R.string.local_file_not_found_toast);
         } else {
             openFileWithDefault(file.getLocalPath());
         }
@@ -190,9 +188,8 @@ public class UploadListActivity extends FileActivity implements UploadListFragme
         try {
             startActivity(myIntent);
         } catch (ActivityNotFoundException e) {
-            Toast.makeText(this, "Found no app to open this file.", Toast.LENGTH_LONG).show();
+            DisplayUtils.showSnackMessage(this, R.string.file_list_no_app_for_file_type);
             Log_OC.i(TAG, "Could not find app for sending log history.");
-
         }        
     }
 

+ 50 - 10
src/main/java/com/owncloud/android/ui/adapter/ExpandableUploadListAdapter.java

@@ -23,6 +23,7 @@ import android.accounts.Account;
 import android.content.Context;
 import android.database.DataSetObserver;
 import android.graphics.Bitmap;
+import android.support.design.widget.Snackbar;
 import android.text.format.DateUtils;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -41,6 +42,7 @@ import com.owncloud.android.datamodel.ThumbnailsCacheManager;
 import com.owncloud.android.datamodel.UploadsStorageManager;
 import com.owncloud.android.datamodel.UploadsStorageManager.UploadStatus;
 import com.owncloud.android.db.OCUpload;
+import com.owncloud.android.db.UploadResult;
 import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
 import com.owncloud.android.lib.common.utils.Log_OC;
@@ -355,13 +357,50 @@ public class ExpandableUploadListAdapter extends BaseExpandableListAdapter imple
             
             view.setOnClickListener(null);
 
+            // retry
+            if (upload.getUploadStatus() == UploadStatus.UPLOAD_FAILED) {
+                if (UploadResult.CREDENTIAL_ERROR.equals(upload.getLastResult())) {
+                    view.setOnClickListener(new View.OnClickListener() {
+                        @Override
+                        public void onClick(View v) {
+                            mParentActivity.getFileOperationsHelper().checkCurrentCredentials(
+                                upload.getAccount(mParentActivity)
+                            );
+                        }
+                    });
+
+                } else {
+                    // not a credentials error
+                    view.setOnClickListener(new View.OnClickListener() {
+                        @Override
+                        public void onClick(View v) {
+                        File file = new File(upload.getLocalPath());
+                        if (file.exists()) {
+                            FileUploader.UploadRequester requester = new FileUploader.UploadRequester();
+                            requester.retry(mParentActivity, upload);
+                            refreshView();
+                        } else {
+                            Snackbar.make(
+                                    v.getRootView().findViewById(android.R.id.content),
+                                    mParentActivity.getString(R.string.local_file_not_found_toast),
+                                    Snackbar.LENGTH_LONG
+                            ).show();
+                        }
+                        }
+                    });
+                }
+            } else {
+                view.setOnClickListener(null);
+            }
+
             /// Set icon or thumbnail
             ImageView fileIcon = (ImageView) view.findViewById(R.id.thumbnail);
             fileIcon.setImageResource(R.drawable.file);
 
-            /** Cancellation needs do be checked and done before changing the drawable in fileIcon, or
+            /*
+             * Cancellation needs do be checked and done before changing the drawable in fileIcon, or
              * {@link ThumbnailsCacheManager#cancelPotentialWork} will NEVER cancel any task.
-             **/
+             */
             OCFile fakeFileToCheatThumbnailsCacheManagerInterface = new OCFile(upload.getRemotePath());
             fakeFileToCheatThumbnailsCacheManagerInterface.setStoragePath(upload.getLocalPath());
             fakeFileToCheatThumbnailsCacheManagerInterface.setMimetype(upload.getMimeType());
@@ -531,11 +570,6 @@ public class ExpandableUploadListAdapter extends BaseExpandableListAdapter imple
                                 R.string.uploads_view_upload_status_service_interrupted
                         );
                         break;
-                    case UNKNOWN:
-                        status = mParentActivity.getString(
-                                R.string.uploads_view_upload_status_unknown_fail
-                        );
-                        break;
                     case CANCELLED:
                         // should not get here ; cancelled uploads should be wiped out
                         status = mParentActivity.getString(
@@ -549,15 +583,21 @@ public class ExpandableUploadListAdapter extends BaseExpandableListAdapter imple
                     case MAINTENANCE_MODE:
                         status = mParentActivity.getString(R.string.maintenance_mode);
                         break;
-                    case LOCK_FAILED:
-                        status = mParentActivity.getString(R.string.lock_failed);
+                    case SSL_RECOVERABLE_PEER_UNVERIFIED:
+                        status =
+                                mParentActivity.getString(
+                                        R.string.uploads_view_upload_status_failed_ssl_certificate_not_trusted
+                                );
+                        break;
+                    case UNKNOWN:
+                        status = mParentActivity.getString(R.string.uploads_view_upload_status_unknown_fail);
                         break;
                     case DELAYED_IN_POWER_SAVE_MODE:
                         status = mParentActivity.getString(
                                 R.string.uploads_view_upload_status_waiting_exit_power_save_mode);
                         break;
                     default:
-                        status = "Naughty devs added a new fail result but no description for the user";
+                        status = "New fail result but no description for the user";
                         break;
                 }
                 break;

+ 5 - 10
src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.java

@@ -31,12 +31,12 @@ import android.view.View;
 import android.view.WindowManager.LayoutParams;
 import android.widget.EditText;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.resources.files.FileUtils;
 import com.owncloud.android.ui.activity.ComponentsGetter;
+import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.ThemeUtils;
 
 /**
@@ -116,23 +116,19 @@ public class CreateFolderDialogFragment
                         .getText().toString().trim();
             
             if (newFolderName.length() <= 0) {
-                Toast.makeText(
-                        getActivity(),
-                        R.string.filename_empty, 
-                        Toast.LENGTH_LONG).show();
+                DisplayUtils.showSnackMessage(getActivity(), R.string.filename_empty);
                 return;
             }
             boolean serverWithForbiddenChars = ((ComponentsGetter)getActivity()).
                     getFileOperationsHelper().isVersionWithForbiddenCharacters();
 
             if (!FileUtils.isValidName(newFolderName, serverWithForbiddenChars)) {
-                int messageId = 0;
+
                 if (serverWithForbiddenChars) {
-                    messageId = R.string.filename_forbidden_charaters_from_server;
+                    DisplayUtils.showSnackMessage(getActivity(), R.string.filename_forbidden_charaters_from_server);
                 } else {
-                    messageId = R.string.filename_forbidden_characters;
+                    DisplayUtils.showSnackMessage(getActivity(), R.string.filename_forbidden_characters);
                 }
-                Toast.makeText(getActivity(), messageId, Toast.LENGTH_LONG).show();
 
                 return;
             }
@@ -143,5 +139,4 @@ public class CreateFolderDialogFragment
                 getFileOperationsHelper().createFolder(path, false);
         }
     }
-        
 }

+ 1 - 1
src/main/java/com/owncloud/android/ui/dialog/CredentialsDialogFragment.java

@@ -139,7 +139,7 @@ public class CredentialsDialogFragment extends DialogFragment
 
         } else if (which == AlertDialog.BUTTON_NEGATIVE) {
             mWebView.stopLoading();
-            ((AuthenticatorActivity)getActivity()).doNegativeAuthenticatioDialogClick();
+            ((AuthenticatorActivity)getActivity()).doNegativeAuthenticationDialogClick();
         }
 
         dialog.dismiss();

+ 6 - 9
src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.java

@@ -37,12 +37,12 @@ import android.view.View;
 import android.view.WindowManager.LayoutParams;
 import android.widget.EditText;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.resources.files.FileUtils;
 import com.owncloud.android.ui.activity.ComponentsGetter;
+import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.ThemeUtils;
 
 
@@ -130,10 +130,7 @@ public class RenameFileDialogFragment
                     .getText().toString().trim();
             
             if (newFileName.length() <= 0) {
-                Toast.makeText(
-                        getActivity(),
-                        R.string.filename_empty, 
-                        Toast.LENGTH_LONG).show();
+                DisplayUtils.showSnackMessage(getActivity(), R.string.filename_empty);
                 return;
             }
 
@@ -141,13 +138,13 @@ public class RenameFileDialogFragment
                     getFileOperationsHelper().isVersionWithForbiddenCharacters();
 
             if (!FileUtils.isValidName(newFileName, serverWithForbiddenChars)) {
-                int messageId = 0;
+
                 if (serverWithForbiddenChars) {
-                    messageId = R.string.filename_forbidden_charaters_from_server;
+                    DisplayUtils.showSnackMessage(getActivity(), R.string.filename_forbidden_charaters_from_server);
                 } else {
-                    messageId = R.string.filename_forbidden_characters;
+                    DisplayUtils.showSnackMessage(getActivity(), R.string.filename_forbidden_characters);
                 }
-                Toast.makeText(getActivity(), messageId, Toast.LENGTH_LONG).show();
+
                 return;
             }
 

+ 5 - 4
src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java

@@ -22,6 +22,7 @@ import android.app.Dialog;
 import android.content.DialogInterface;
 import android.graphics.PorterDuff;
 import android.os.Bundle;
+import android.support.design.widget.Snackbar;
 import android.support.v4.app.DialogFragment;
 import android.support.v7.app.AlertDialog;
 import android.view.LayoutInflater;
@@ -29,7 +30,6 @@ import android.view.View;
 import android.view.WindowManager;
 import android.widget.EditText;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
@@ -115,10 +115,11 @@ public class SharePasswordDialogFragment extends DialogFragment
                         .getText().toString();
 
             if (password.length() <= 0) {
-                Toast.makeText(
-                        getActivity(),
+                Snackbar.make(
+                        getActivity().findViewById(android.R.id.content),
                         R.string.share_link_empty_password,
-                        Toast.LENGTH_LONG).show();
+                        Snackbar.LENGTH_LONG
+                ).show();
                 return;
             }
 

+ 18 - 16
src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java

@@ -56,7 +56,6 @@ import android.widget.ListView;
 import android.widget.PopupMenu;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
@@ -391,16 +390,18 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
      * registers all listeners on all mini FABs.
      */
     private void registerFabListeners() {
-        registerFabUploadListeners();
-        registerFabMkDirListeners();
-        registerFabUploadFromAppListeners();
+        registerFabUploadListeners(getActivity());
+        registerFabMkDirListeners(getActivity());
+        registerFabUploadFromAppListeners(getActivity());
     }
 
     /**
      * registers {@link android.view.View.OnClickListener} and {@link android.view.View.OnLongClickListener}
-     * on the Upload mini FAB for the linked action and {@link Toast} showing the underlying action.
+     * on the Upload mini FAB for the linked action and {@link Snackbar} showing the underlying action.
+     *
+     * @param activity the activity on which's content the {@link Snackbar} will be shown.
      */
-    private void registerFabUploadListeners() {
+    private void registerFabUploadListeners(final Activity activity) {
         getFabUpload().setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
@@ -414,7 +415,7 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
         getFabUpload().setOnLongClickListener(new View.OnLongClickListener() {
             @Override
             public boolean onLongClick(View v) {
-                Toast.makeText(getActivity(), R.string.actionbar_upload, Toast.LENGTH_SHORT).show();
+                DisplayUtils.showSnackMessage(activity, R.string.actionbar_upload);
                 return true;
             }
         });
@@ -422,9 +423,11 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
 
     /**
      * registers {@link android.view.View.OnClickListener} and {@link android.view.View.OnLongClickListener}
-     * on the 'Create Dir' mini FAB for the linked action and {@link Toast} showing the underlying action.
+     * on the 'Create Dir' mini FAB for the linked action and {@link Snackbar} showing the underlying action.
+     *
+     * @param activity the activity on which's content the {@link Snackbar} will be shown.
      */
-    private void registerFabMkDirListeners() {
+    private void registerFabMkDirListeners(final Activity activity) {
         getFabMkdir().setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
@@ -439,7 +442,7 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
         getFabMkdir().setOnLongClickListener(new View.OnLongClickListener() {
             @Override
             public boolean onLongClick(View v) {
-                Toast.makeText(getActivity(), R.string.actionbar_mkdir, Toast.LENGTH_SHORT).show();
+                DisplayUtils.showSnackMessage(activity, R.string.actionbar_mkdir);
                 return true;
             }
         });
@@ -447,9 +450,11 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
 
     /**
      * registers {@link android.view.View.OnClickListener} and {@link android.view.View.OnLongClickListener}
-     * on the Upload from App mini FAB for the linked action and {@link Toast} showing the underlying action.
+     * on the Upload from App mini FAB for the linked action and {@link Snackbar} showing the underlying action.
+     *
+     * @param activity the activity on which's content the {@link Snackbar} will be shown.
      */
-    private void registerFabUploadFromAppListeners() {
+    private void registerFabUploadFromAppListeners(final Activity activity) {
         getFabUploadFromApp().setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
@@ -471,9 +476,7 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
         getFabUploadFromApp().setOnLongClickListener(new View.OnLongClickListener() {
             @Override
             public boolean onLongClick(View v) {
-                Toast.makeText(getActivity(),
-                        R.string.actionbar_upload_from_apps,
-                        Toast.LENGTH_SHORT).show();
+                DisplayUtils.showSnackMessage(activity, R.string.actionbar_upload_from_apps);
                 return true;
             }
         });
@@ -1662,5 +1665,4 @@ public class OCFileListFragment extends ExtendedListFragment implements OCFileLi
             listView.setItemChecked(position, select);
         }
     }
-
 }

+ 5 - 3
src/main/java/com/owncloud/android/ui/fragment/ShareFileFragment.java

@@ -43,7 +43,6 @@ import android.widget.ListAdapter;
 import android.widget.ListView;
 import android.widget.ScrollView;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.AccountUtils;
@@ -247,8 +246,11 @@ public class ShareFileFragment extends Fragment implements ShareUserListAdapter.
                     // Show Search Fragment
                     mListener.showSearchUsersAndGroups();
                 } else {
-                    String message = getString(R.string.share_sharee_unavailable);
-                    Toast.makeText(getActivity(), message, Toast.LENGTH_LONG).show();
+                    Snackbar.make(
+                            getActivity().findViewById(android.R.id.content),
+                            getString(R.string.share_sharee_unavailable),
+                            Snackbar.LENGTH_LONG
+                    ).show();
                 }
             }
         });

+ 7 - 34
src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java

@@ -49,6 +49,7 @@ import com.owncloud.android.services.observer.FileObserverService;
 import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.activity.ShareActivity;
 import com.owncloud.android.ui.events.FavoriteEvent;
+import com.owncloud.android.utils.DisplayUtils;
 
 import org.greenrobot.eventbus.EventBus;
 
@@ -182,10 +183,10 @@ public class FileOperationsHelper {
                 try {
                     mFileActivity.startActivity(openFileWithIntent);
                 } catch (ActivityNotFoundException anfe) {
-                    showNoAppForFileTypeToast(mFileActivity.getApplicationContext());
+                    DisplayUtils.showSnackMessage(mFileActivity, R.string.file_list_no_app_for_file_type);
                 }
             } else {
-                showNoAppForFileTypeToast(mFileActivity.getApplicationContext());
+                DisplayUtils.showSnackMessage(mFileActivity, R.string.file_list_no_app_for_file_type);
             }
 
         } else {
@@ -193,18 +194,6 @@ public class FileOperationsHelper {
         }
     }
 
-    /**
-     * Displays a toast stating that no application could be found to open the file.
-     *
-     * @param context the context to be able to show a toast.
-     */
-    private void showNoAppForFileTypeToast(Context context) {
-        Toast.makeText(context,
-                R.string.file_list_no_app_for_file_type, Toast.LENGTH_SHORT)
-                .show();
-    }
-
-
     /**
      * Helper method to share a file via a public link. Starts a request to do it in {@link OperationsService}
      *
@@ -214,10 +203,7 @@ public class FileOperationsHelper {
     public void shareFileViaLink(OCFile file, String password) {
         if (isSharedSupported()) {
             if (file != null) {
-                mFileActivity.showLoadingDialog(
-                        mFileActivity.getApplicationContext().
-                                getString(R.string.wait_a_moment)
-                );
+                mFileActivity.showLoadingDialog(mFileActivity.getString(R.string.wait_a_moment));
                 Intent service = new Intent(mFileActivity, OperationsService.class);
                 service.setAction(OperationsService.ACTION_CREATE_SHARE_VIA_LINK);
                 service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
@@ -234,11 +220,7 @@ public class FileOperationsHelper {
 
         } else {
             // Show a Message
-            Toast t = Toast.makeText(
-                    mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api),
-                    Toast.LENGTH_LONG
-            );
-            t.show();
+            DisplayUtils.showSnackMessage(mFileActivity, R.string.share_link_no_support_share_api);
         }
     }
 
@@ -259,11 +241,7 @@ public class FileOperationsHelper {
             }
         } else {
             // Show a Message
-            Toast t = Toast.makeText(
-                    mFileActivity, mFileActivity.getString(R.string.share_link_no_support_share_api),
-                    Toast.LENGTH_LONG
-            );
-            t.show();
+            DisplayUtils.showSnackMessage(mFileActivity, R.string.share_link_no_support_share_api);
         }
     }
 
@@ -352,11 +330,7 @@ public class FileOperationsHelper {
 
         } else {
             // Show a Message
-            Toast t = Toast.makeText(mFileActivity,
-                    mFileActivity.getString(R.string.share_link_no_support_share_api),
-                    Toast.LENGTH_LONG);
-            t.show();
-
+            DisplayUtils.showSnackMessage(mFileActivity, R.string.share_link_no_support_share_api);
         }
     }
 
@@ -370,7 +344,6 @@ public class FileOperationsHelper {
         intent.putExtra(FileActivity.EXTRA_FILE, file);
         intent.putExtra(FileActivity.EXTRA_ACCOUNT, mFileActivity.getAccount());
         mFileActivity.startActivity(intent);
-
     }
 
 

+ 37 - 0
src/main/java/com/owncloud/android/utils/DisplayUtils.java

@@ -38,7 +38,9 @@ import android.graphics.drawable.PictureDrawable;
 import android.net.Uri;
 import android.os.Build;
 import android.support.annotation.NonNull;
+import android.support.annotation.StringRes;
 import android.support.design.widget.BottomNavigationView;
+import android.support.design.widget.Snackbar;
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
 import android.text.format.DateUtils;
@@ -623,4 +625,39 @@ public class DisplayUtils {
         }
         return text.toString();
     }
+
+    /**
+     * Show a temporary message in a Snackbar bound to the content view.
+     *
+     * @param activity Activity to which's content view the Snackbar is bound.
+     * @param messageResource Message to show.
+     */
+    public static void showSnackMessage(Activity activity, @StringRes int messageResource) {
+        Snackbar.make(activity.findViewById(android.R.id.content), messageResource, Snackbar.LENGTH_LONG).show();
+    }
+
+    /**
+     * Show a temporary message in a Snackbar bound to the content view.
+     *
+     * @param activity        Activity to which's content view the Snackbar is bound.
+     * @param messageResource Resource id for the format string - message to show.
+     * @param formatArgs      The format arguments that will be used for substitution.
+     */
+    public static void showSnackMessage(Activity activity, @StringRes int messageResource, Object... formatArgs) {
+        Snackbar.make(
+                activity.findViewById(android.R.id.content),
+                String.format(activity.getString(messageResource, formatArgs)),
+                Snackbar.LENGTH_LONG)
+                .show();
+    }
+
+    /**
+     * Show a temporary message in a Snackbar bound to the content view.
+     *
+     * @param activity Activity to which's content view the Snackbar is bound.
+     * @param message Message to show.
+     */
+    public static void showSnackMessage(Activity activity, String message) {
+        Snackbar.make(activity.findViewById(android.R.id.content), message, Snackbar.LENGTH_LONG).show();
+    }
 }

+ 372 - 190
src/main/java/com/owncloud/android/utils/ErrorMessageAdapter.java

@@ -1,25 +1,29 @@
 /**
- * ownCloud Android client application
+ *   ownCloud Android client application
  *
- * @author masensio
- * Copyright (C) 2014 ownCloud Inc.
+ *   @author masensio
+ *   Copyright (C) 2016 ownCloud GmbH.
  *
- * 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 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.
+ *   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 <http://www.gnu.org/licenses/>.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+
 package com.owncloud.android.utils;
 
 import android.content.res.Resources;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 
 import com.owncloud.android.R;
 import com.owncloud.android.lib.common.operations.RemoteOperation;
@@ -47,245 +51,329 @@ import java.net.SocketTimeoutException;
 
 /**
  * Class to choose proper error messages to show to the user depending on the results of operations,
- * always following the same policy.
+ * always following the same policy
  */
 public class ErrorMessageAdapter {
+    /**
+     * Return an internationalized user message corresponding to an operation result
+     * and the operation performed.
+     *
+     * @param result        Result of a {@link RemoteOperation} performed.
+     * @param operation     Operation performed.
+     * @param res           Reference to app resources, for i18n.
+     * @return              User message corresponding to 'result' and 'operation'.
+     */
+    @NonNull
+    public static String getErrorCauseMessage(
+            RemoteOperationResult result,
+            RemoteOperation operation,
+            Resources res
+    ) {
+        String message = getSpecificMessageForResultAndOperation(result, operation, res);
+
+        if (message == null || message.length() <= 0) {
+            message = getCommonMessageForResult(result, res);
+        }
 
-    public static String getErrorCauseMessage(RemoteOperationResult result,
-                                              RemoteOperation operation, Resources res) {
-
-        String message = null;
-
-        if (!result.isSuccess() && isCommonError(result.getCode())) {
-            message = getCommonErrorMessage(result, res);
-
-        } else if (operation instanceof UploadFileOperation) {
+        if (message == null || message.length() <= 0) {
+            message = getGenericErrorMessageForOperation(operation, res);
+        }
 
+        if (message == null) {
             if (result.isSuccess()) {
-                message = String.format(
-                        res.getString(R.string.uploader_upload_succeeded_content_single),
-                        ((UploadFileOperation) operation).getFileName());
+                message = res.getString(R.string.common_ok);
+
             } 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(),
-                            res.getString(R.string.app_name));
-                /*
-                } else if (result.getCode() == ResultCode.QUOTA_EXCEEDED) {
-                    message = res.getString(R.string.failed_upload_quota_exceeded_text);
-                    */
-
-                } else if (result.getCode() == ResultCode.FORBIDDEN) {
-                    message = String.format(res.getString(R.string.forbidden_permissions),
-                            res.getString(R.string.uploader_upload_forbidden_permissions));
-
-                } else if (result.getCode() == ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER) {
-                    message = res.getString(R.string.filename_forbidden_charaters_from_server);
-
-                } else {
-                    message = String.format(
-                            res.getString(R.string.uploader_upload_failed_content_single),
-                            ((UploadFileOperation) operation).getFileName());
-                }
+                message = res.getString(R.string.common_error_unknown);
             }
+        }
 
-        } else if (operation instanceof DownloadFileOperation) {
+        return message;
+    }
 
-            if (result.isSuccess()) {
-                message = String.format(
-                        res.getString(R.string.downloader_download_succeeded_content),
-                        new File(((DownloadFileOperation) operation).getSavePath()).getName());
+    /**
+     * Return a user message corresponding to an operation result and specific for the operation
+     * performed.
+     *
+     * @param result        Result of a {@link RemoteOperation} performed.
+     * @param operation     Operation performed.
+     * @param res           Reference to app resources, for i18n.
+     * @return              User message corresponding to 'result' and 'operation', or NULL if there is no
+     *                      specific message for both.
+     */
+    @Nullable
+    private static String getSpecificMessageForResultAndOperation(
+            RemoteOperationResult result,
+            RemoteOperation operation,
+            Resources res
+    ) {
 
-            } else {
-                if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
-                    message = res.getString(R.string.downloader_download_file_not_found);
+        String message = null;
 
-                } else {
-                    message = String.format(
-                            res.getString(R.string.downloader_download_failed_content), new File(
-                                    ((DownloadFileOperation) operation).getSavePath()).getName());
-                }
-            }
+        if (operation instanceof UploadFileOperation) {
+            message = getMessageForUploadFileOperation(result, (UploadFileOperation) operation, res);
+
+        } else if (operation instanceof DownloadFileOperation) {
+            message = getMessageForDownloadFileOperation(result, (DownloadFileOperation) operation, res);
 
         } else if (operation instanceof RemoveFileOperation) {
-            if (result.isSuccess()) {
-                message = res.getString(R.string.remove_success_msg);
+            message = getMessageForRemoveFileOperation(result, res);
 
-            } else {
-                if (result.getCode().equals(ResultCode.FORBIDDEN)) {
-                    // Error --> No permissions
-                    message = String.format(res.getString(R.string.forbidden_permissions),
-                            res.getString(R.string.forbidden_permissions_delete));
+        } else if (operation instanceof RenameFileOperation) {
+            message = getMessageForRenameFileOperation(result, res);
 
-                } else {
-                    message = res.getString(R.string.remove_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 RenameFileOperation) {
-            if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {
-                message = res.getString(R.string.rename_local_fail_msg);
+        } else if (operation instanceof CreateFolderOperation) {
+            message = getMessageForCreateFolderOperation(result, res);
 
-            } else if (result.getCode().equals(ResultCode.FORBIDDEN)) {
-                // Error --> No permissions
-                message = String.format(res.getString(R.string.forbidden_permissions),
-                        res.getString(R.string.forbidden_permissions_rename));
+        } else if (operation instanceof CreateShareViaLinkOperation ||
+                operation instanceof CreateShareWithShareeOperation) {
 
-            } else if (result.getCode().equals(ResultCode.INVALID_CHARACTER_IN_NAME)) {
-                message = res.getString(R.string.filename_forbidden_characters);
+            message = getMessageForCreateShareOperations(result, res);
 
-            } else if (result.getCode() == ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER) {
-                message = res.getString(R.string.filename_forbidden_charaters_from_server);
+        } else if (operation instanceof UnshareOperation) {
 
-            } else {
-                message = res.getString(R.string.rename_server_fail_msg);
-            }
+            message = getMessageForUnshareOperation(result, res);
 
-        } else if (operation instanceof SynchronizeFileOperation) {
-            if (!((SynchronizeFileOperation) operation).transferWasRequested()) {
-                message = res.getString(R.string.sync_file_nothing_to_do_msg);
-            }
+        } else if (operation instanceof UpdateShareViaLinkOperation ||
+                operation instanceof UpdateSharePermissionsOperation) {
 
-        } else if (operation instanceof CreateFolderOperation) {
-            if (result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME) {
-                message = res.getString(R.string.filename_forbidden_characters);
+            message = getMessageForUpdateShareOperations(result, res);
 
-            } else if (result.getCode().equals(ResultCode.FORBIDDEN)) {
-                message = String.format(res.getString(R.string.forbidden_permissions),
-                        res.getString(R.string.forbidden_permissions_create));
+        } else if (operation instanceof MoveFileOperation) {
 
-            } else if (result.getCode() == ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER) {
-                message = res.getString(R.string.filename_forbidden_charaters_from_server);
+            message = getMessageForMoveFileOperation(result, res);
 
-            } else {
-                message = res.getString(R.string.create_dir_fail_msg);
-            }
+        } else if (operation instanceof SynchronizeFolderOperation) {
 
-        } else if (operation instanceof CreateShareViaLinkOperation ||
-                operation instanceof CreateShareWithShareeOperation) {
+            message = getMessageForSynchronizeFolderOperation(result, (SynchronizeFolderOperation) operation, res);
 
-            if (result.getData() != null && result.getData().size() > 0) {
-                message = (String) result.getData().get(0);     // share API sends its own error messages
+        } else if (operation instanceof CopyFileOperation) {
+            message = getMessageForCopyFileOperation(result, res);
+        }
 
-            } else if (result.getCode() == ResultCode.SHARE_NOT_FOUND) {
-                message = res.getString(R.string.share_link_file_no_exist);
+        return message;
+    }
 
-            } else if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
-                // Error --> No permissions
-                message = String.format(res.getString(R.string.forbidden_permissions),
-                        res.getString(R.string.share_link_forbidden_permissions));
+    private static String getMessageForSynchronizeFolderOperation(
+            RemoteOperationResult result,
+            SynchronizeFolderOperation operation,
+            Resources res
+    ) {
+        if (!result.isSuccess() && result.getCode() == ResultCode.FILE_NOT_FOUND) {
+            return String.format(
+                    res.getString(R.string.sync_current_folder_was_removed),
+                    new File(operation.getFolderPath()).getName()
+            );
+        }
+        return
+                null;
+    }
 
-            } else {    // Generic error
-                // Show a Message, operation finished without success
-                message = res.getString(R.string.share_link_file_error);
-            }
+    private static String getMessageForMoveFileOperation(RemoteOperationResult result, Resources res) {
+        if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
+            return res.getString(R.string.move_file_not_found);
+        } else if (result.getCode() == ResultCode.INVALID_MOVE_INTO_DESCENDANT) {
+            return res.getString(R.string.move_file_invalid_into_descendent);
 
-        } else if (operation instanceof UnshareOperation) {
+        } else if (result.getCode() == ResultCode.INVALID_OVERWRITE) {
+            return res.getString(R.string.move_file_invalid_overwrite);
 
-            if (result.getData() != null && result.getData().size() > 0) {
-                message = (String) result.getData().get(0);     // share API sends its own error messages
+        } else if (result.getCode() == ResultCode.FORBIDDEN) {
+            return String.format(res.getString(R.string.forbidden_permissions),
+                    res.getString(R.string.forbidden_permissions_move));
 
-            } else if (result.getCode() == ResultCode.SHARE_NOT_FOUND) {
-                message = res.getString(R.string.unshare_link_file_no_exist);
+        } else if (result.getCode() == ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER) {
+            return res.getString(R.string.filename_forbidden_charaters_from_server);
+        }
+        return null;
+    }
 
-            } else if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
-                // Error --> No permissions
-                message = String.format(res.getString(R.string.forbidden_permissions),
-                        res.getString(R.string.unshare_link_forbidden_permissions));
+    private static String getMessageForUpdateShareOperations(RemoteOperationResult result, Resources res) {
+        if (result.getData() != null && result.getData().size() > 0) {
+            return (String) result.getData().get(0);     // share API sends its own error messages
 
-            } else {    // Generic error
-                // Show a Message, operation finished without success
-                message = res.getString(R.string.unshare_link_file_error);
-            }
+        } else if (result.getCode() == ResultCode.SHARE_NOT_FOUND) {
+            return res.getString(R.string.update_link_file_no_exist);
 
-        } else if (operation instanceof UpdateShareViaLinkOperation ||
-                operation instanceof UpdateSharePermissionsOperation) {
+        } else if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
+            // Error --> No permissions
+            return String.format(res.getString(R.string.forbidden_permissions),
+                    res.getString(R.string.update_link_forbidden_permissions));
 
-            if (result.getData() != null && result.getData().size() > 0) {
-                message = (String) result.getData().get(0);     // share API sends its own error messages
+        }
+        return null;
+    }
 
-            } else if (result.getCode() == ResultCode.SHARE_NOT_FOUND) {
-                message = res.getString(R.string.update_link_file_no_exist);
+    private static String getMessageForUnshareOperation(RemoteOperationResult result, Resources res) {
+        if (result.getData() != null && result.getData().size() > 0) {
+            return (String) result.getData().get(0);     // share API sends its own error messages
 
-            } else if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
-                // Error --> No permissions
-                message = String.format(res.getString(R.string.forbidden_permissions),
-                        res.getString(R.string.update_link_forbidden_permissions));
+        } else if (result.getCode() == ResultCode.SHARE_NOT_FOUND) {
+            return res.getString(R.string.unshare_link_file_no_exist);
 
-            } else {    // Generic error
-                // Show a Message, operation finished without success
-                message = res.getString(R.string.update_link_file_error);
-            }
+        } else if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
+            // Error --> No permissions
+            return String.format(res.getString(R.string.forbidden_permissions),
+                    res.getString(R.string.unshare_link_forbidden_permissions));
 
-        } else if (operation instanceof MoveFileOperation) {
+        }
+        return null;
+    }
 
-            if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
-                message = res.getString(R.string.move_file_not_found);
-            } else if (result.getCode() == ResultCode.INVALID_MOVE_INTO_DESCENDANT) {
-                message = res.getString(R.string.move_file_invalid_into_descendent);
+    private static String getMessageForCopyFileOperation(RemoteOperationResult result, Resources res) {
+        if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
+            return res.getString(R.string.copy_file_not_found);
 
-            } else if (result.getCode() == ResultCode.INVALID_OVERWRITE) {
-                message = res.getString(R.string.move_file_invalid_overwrite);
+        } else if (result.getCode() == ResultCode.INVALID_COPY_INTO_DESCENDANT) {
+            return res.getString(R.string.copy_file_invalid_into_descendent);
 
-            } else if (result.getCode() == ResultCode.FORBIDDEN) {
-                message = String.format(res.getString(R.string.forbidden_permissions),
-                        res.getString(R.string.forbidden_permissions_move));
+        } else if (result.getCode() == ResultCode.INVALID_OVERWRITE) {
+            return res.getString(R.string.copy_file_invalid_overwrite);
 
-            } else if (result.getCode() == ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER) {
-                message = res.getString(R.string.filename_forbidden_charaters_from_server);
+        } else if (result.getCode() == ResultCode.FORBIDDEN) {
+            return String.format(res.getString(R.string.forbidden_permissions),
+                    res.getString(R.string.forbidden_permissions_copy));
 
-            } else {    // Generic error
-                // Show a Message, operation finished without success
-                message = res.getString(R.string.move_file_error);
-            }
+        }
+        return null;
+    }
 
-        } else if (operation instanceof SynchronizeFolderOperation) {
+    private static String getMessageForCreateShareOperations(RemoteOperationResult result, Resources res) {
+        if (result.getData() != null && result.getData().size() > 0) {
+            return (String) result.getData().get(0);     // share API sends its own error messages
 
-            if (!result.isSuccess()) {
-                String folderPathName = new File(
-                        ((SynchronizeFolderOperation) operation).getFolderPath()).getName();
-                if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
-                    message = String.format(res.getString(R.string.sync_current_folder_was_removed),
-                            folderPathName);
-
-                } else {    // Generic error
-                    // Show a Message, operation finished without success
-                    message = String.format(res.getString(R.string.sync_folder_failed_content),
-                            folderPathName);
-                }
+        } else if (result.getCode() == ResultCode.SHARE_NOT_FOUND)  {
+            return res.getString(R.string.share_link_file_no_exist);
+
+        } else if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
+            // Error --> No permissions
+            return String.format(res.getString(R.string.forbidden_permissions),
+                    res.getString(R.string.share_link_forbidden_permissions));
+
+        }
+        return null;
+    }
+
+    private static String getMessageForCreateFolderOperation(RemoteOperationResult result, Resources res) {
+        if (result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME) {
+            return res.getString(R.string.filename_forbidden_characters);
+
+        } else if (result.getCode().equals(ResultCode.FORBIDDEN)) {
+            return String.format(res.getString(R.string.forbidden_permissions),
+                    res.getString(R.string.forbidden_permissions_create));
+
+        } else if (result.getCode() == ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER) {
+            return res.getString(R.string.filename_forbidden_charaters_from_server);
+
+        }
+        return null;
+    }
+
+    private static String getMessageForRenameFileOperation(RemoteOperationResult result, Resources res) {
+        if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {
+            return res.getString(R.string.rename_local_fail_msg);
+
+        } else if (result.getCode().equals(ResultCode.FORBIDDEN)) {
+            // Error --> No permissions
+            return String.format(res.getString(R.string.forbidden_permissions),
+                    res.getString(R.string.forbidden_permissions_rename));
+
+        } else if (result.getCode().equals(ResultCode.INVALID_CHARACTER_IN_NAME)) {
+            return res.getString(R.string.filename_forbidden_characters);
+
+        } else if (result.getCode() == ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER) {
+            return res.getString(R.string.filename_forbidden_charaters_from_server);
+
+        }
+
+        return null;
+    }
+
+    private static String getMessageForRemoveFileOperation(RemoteOperationResult result, Resources res) {
+        if (result.isSuccess()) {
+            return res.getString(R.string.remove_success_msg);
+
+        } else {
+            if (result.getCode().equals(ResultCode.FORBIDDEN)) {
+                // Error --> No permissions
+                return String.format(res.getString(R.string.forbidden_permissions),
+                        res.getString(R.string.forbidden_permissions_delete));
             }
+        }
 
-        } else if (operation instanceof CopyFileOperation) {
+        return null;
+    }
+
+    private static String getMessageForDownloadFileOperation(
+            RemoteOperationResult result,
+            DownloadFileOperation operation,
+            Resources res
+    ) {
+        if (result.isSuccess()) {
+            return String.format(
+                    res.getString(R.string.downloader_download_succeeded_content),
+                    new File(operation.getSavePath()).getName());
+
+        } else {
             if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
-                message = res.getString(R.string.copy_file_not_found);
+                return res.getString(R.string.downloader_download_file_not_found);
 
-            } else if (result.getCode() == ResultCode.INVALID_COPY_INTO_DESCENDANT) {
-                message = res.getString(R.string.copy_file_invalid_into_descendent);
+            }
+        }
+        return null;
+    }
 
-            } else if (result.getCode() == ResultCode.INVALID_OVERWRITE) {
-                message = res.getString(R.string.copy_file_invalid_overwrite);
+    private static String getMessageForUploadFileOperation(
+            RemoteOperationResult result,
+            UploadFileOperation operation,
+            Resources res
+    ) {
+        if (result.isSuccess()) {
+            return String.format(
+                    res.getString(R.string.uploader_upload_succeeded_content_single),
+                    operation.getFileName());
+        } else {
+
+            if (result.getCode() == ResultCode.LOCAL_STORAGE_FULL
+                    || result.getCode() == ResultCode.LOCAL_STORAGE_NOT_COPIED) {
+                return String.format(
+                        res.getString(R.string.error__upload__local_file_not_copied),
+                        operation.getFileName(),
+                        res.getString(R.string.app_name));
 
             } else if (result.getCode() == ResultCode.FORBIDDEN) {
-                message = String.format(res.getString(R.string.forbidden_permissions),
-                        res.getString(R.string.forbidden_permissions_copy));
+                return String.format(res.getString(R.string.forbidden_permissions),
+                        res.getString(R.string.uploader_upload_forbidden_permissions));
+
+            } else if (result.getCode() == ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER) {
+                return res.getString(R.string.filename_forbidden_charaters_from_server);
 
-            } else {    // Generic error
-                // Show a Message, operation finished without success
-                message = res.getString(R.string.copy_file_error);
             }
         }
 
-        return message;
+        return null;
     }
 
-    private static String getCommonErrorMessage(RemoteOperationResult result, Resources res) {
+
+    /**
+     * Return a user message corresponding to an operation result with no knowledge about the operation
+     * performed.
+     *
+     * @param result        Result of a {@link RemoteOperation} performed.
+     * @param res           Reference to app resources, for i18n.
+     * @return              User message corresponding to 'result'.
+     */
+    @Nullable
+    private static String getCommonMessageForResult(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);
 
@@ -294,24 +382,118 @@ public class ErrorMessageAdapter {
 
                 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);
+
             } else if (result.getCode() == ResultCode.MAINTENANCE_MODE) {
                 message = res.getString(R.string.maintenance_mode);
+
+            } else if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {
+                message = res.getString(R.string.uploads_view_upload_status_failed_ssl_certificate_not_trusted);
+
+            } else if (result.getCode() == ResultCode.BAD_OC_VERSION) {
+                message = res.getString(R.string.auth_bad_oc_version_title);
+
+            } else if (result.getCode() == ResultCode.INCORRECT_ADDRESS) {
+                message = res.getString(R.string.auth_incorrect_address_title);
+
+            } else if (result.getCode() == ResultCode.SSL_ERROR) {
+                message = res.getString(R.string.auth_ssl_general_error_title);
+
+            } else if (result.getCode() == ResultCode.UNAUTHORIZED) {
+                message = res.getString(R.string.auth_unauthorized);
+
+            } else if (result.getCode() == ResultCode.INSTANCE_NOT_CONFIGURED) {
+                message = res.getString(R.string.auth_not_configured_title);
+
+            } else if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
+                message = res.getString(R.string.auth_incorrect_path_title);
+
+            } else if (result.getCode() == ResultCode.OAUTH2_ERROR) {
+                message = res.getString(R.string.auth_oauth_error);
+
+            } else if (result.getCode() == ResultCode.OAUTH2_ERROR_ACCESS_DENIED) {
+                message = res.getString(R.string.auth_oauth_error_access_denied);
+
+            } else if (result.getCode() == ResultCode.ACCOUNT_NOT_NEW) {
+                message = res.getString(R.string.auth_account_not_new);
+
+            } else if (result.getCode() == ResultCode.ACCOUNT_NOT_THE_SAME) {
+                message = res.getString(R.string.auth_account_not_the_same);
+
+            }
+
+            else if (result.getHttpPhrase() != null && result.getHttpPhrase().length() > 0) {
+                // last chance: error message from server
+                message = result.getHttpPhrase();
             }
         }
 
         return message;
     }
 
-    private static boolean isCommonError(RemoteOperationResult.ResultCode code) {
-        return code == ResultCode.WRONG_CONNECTION ||
-                code == ResultCode.TIMEOUT ||
-                code == ResultCode.HOST_NOT_AVAILABLE ||
-                code == ResultCode.MAINTENANCE_MODE;
+    /**
+     * Return a user message corresponding to a generic error for a given operation.
+     *
+     * @param operation     Operation performed.
+     * @param res           Reference to app resources, for i18n.
+     * @return              User message corresponding to a generic error of 'operation'.
+     */
+    @Nullable
+    private static String getGenericErrorMessageForOperation(RemoteOperation operation, Resources res) {
+        String message = null;
+
+        if (operation instanceof UploadFileOperation) {
+            message = String.format(
+                    res.getString(R.string.uploader_upload_failed_content_single),
+                    ((UploadFileOperation) operation).getFileName());
+
+        } else if (operation instanceof DownloadFileOperation) {
+            message = String.format(
+                    res.getString(R.string.downloader_download_failed_content),
+                    new File(((DownloadFileOperation) operation).getSavePath()).getName()
+            );
+
+        } else if (operation instanceof RemoveFileOperation) {
+            message = res.getString(R.string.remove_fail_msg);
+
+        } else if (operation instanceof RenameFileOperation) {
+            message = res.getString(R.string.rename_server_fail_msg);
+
+        } else if (operation instanceof CreateFolderOperation) {
+            message = res.getString(R.string.create_dir_fail_msg);
+
+        } else if (operation instanceof CreateShareViaLinkOperation ||
+                operation instanceof CreateShareWithShareeOperation
+                ) {
+            message = res.getString(R.string.share_link_file_error);
+
+        } else if (operation instanceof UnshareOperation) {
+            message = res.getString(R.string.unshare_link_file_error);
+
+        } else if (operation instanceof UpdateShareViaLinkOperation ||
+                operation instanceof UpdateSharePermissionsOperation
+                ) {
+            message = res.getString(R.string.update_link_file_error);
+
+        } else if (operation instanceof MoveFileOperation) {
+            message = res.getString(R.string.move_file_error);
+
+        } else if (operation instanceof SynchronizeFolderOperation) {
+            String folderPathName = new File(
+                    ((SynchronizeFolderOperation) operation).getFolderPath()
+            ).getName();
+            message = String.format(res.getString(R.string.sync_folder_failed_content), folderPathName);
+
+        } else if (operation instanceof CopyFileOperation) {
+            message = res.getString(R.string.copy_file_error);
+        }
+
+        return message;
     }
 }

+ 0 - 2
src/main/res/layout/edit_share_layout.xml

@@ -60,7 +60,6 @@
             android:layout_gravity="start"
             android:layout_marginTop="@dimen/standard_half_margin"
             android:textColor="@color/color_accent"
-            android:paddingLeft="@dimen/zero"
             style="@style/TextAppearance.AppCompat.Body2"
             />
 
@@ -96,7 +95,6 @@
             android:layout_gravity="start"
             android:layout_marginTop="@dimen/standard_half_margin"
             android:textColor="@color/color_accent"
-            android:paddingLeft="@dimen/zero"
             style="@style/TextAppearance.AppCompat.Body2"
             />
     </LinearLayout>

+ 3 - 1
src/main/res/values/strings.xml

@@ -110,6 +110,7 @@
     <string name="file_list_empty_text_photos_filter">Your search returned no photos.</string>
     <string name="file_list_empty_text_videos">Upload some videos or activate auto upload.</string>
     <string name="file_list_empty_text_videos_filter">Your search returned no videos.</string>
+    <string name="file_item_metadata_separator" translatable="false">,</string>
     <string name="upload_list_empty_headline">No uploads available</string>
     <string name="upload_list_empty_text">Upload some content or activate instant uploading.</string>
     <string name="upload_list_empty_text_auto_upload">Upload some content or activate auto upload.</string>
@@ -150,6 +151,7 @@
     <string name="uploader_upload_failed_ticker">Upload failed</string>
     <string name="uploader_upload_failed_content_single">Could not upload %1$s</string>
     <string name="uploader_upload_failed_credentials_error">Upload failed, you need to log in again</string>
+    <string name="uploads_view_upload_status_failed_ssl_certificate_not_trusted">Server certificate is not trusted</string>
     <string name="uploads_view_title">Uploads</string>
     <string name="uploads_view_group_current_uploads">Current</string>
     <string name="uploads_view_group_failed_uploads">Failed / Pending restart</string>
@@ -300,7 +302,7 @@
     <string name="oauth_check_onoff">Log in with OAuth 2.0</string> 
     <string name="oauth_login_connection">Connecting to OAuth 2.0 server&#8230;</string>
         
-    <string name="ssl_validator_header">The identity of the site could not be verified</string>
+    <string name="ssl_validator_header">The identity of the server could not be verified</string>
     <string name="ssl_validator_reason_cert_not_trusted">- The server certificate is not trusted</string>
     <string name="ssl_validator_reason_cert_expired">- The server certificate expired</string>
     <string name="ssl_validator_reason_cert_not_yet_valid">- The server certificate valid dates are in the future</string>