Merge branch 'develop' into idn_hosts
authorjabarros <jabarros@solidgear.es>
Thu, 23 Oct 2014 09:20:09 +0000 (11:20 +0200)
committerjabarros <jabarros@solidgear.es>
Thu, 23 Oct 2014 09:20:09 +0000 (11:20 +0200)
1  2 
src/com/owncloud/android/authentication/AuthenticatorActivity.java
src/com/owncloud/android/ui/activity/Preferences.java

@@@ -85,7 -85,6 +85,7 @@@ import com.owncloud.android.ui.dialog.I
  import com.owncloud.android.ui.dialog.SamlWebViewDialog;\r
  import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;\r
  import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener;\r
 +import com.owncloud.android.utils.DisplayUtils;\r
  \r
  /**\r
   * This Activity is used to add an ownCloud account to the App\r
@@@ -247,13 -246,17 +247,17 @@@ SsoWebViewClientListener, OnSslUntruste
              if (mAccount != null) {\r
                  boolean oAuthRequired = \r
                      (mAccountMgr.getUserData(mAccount, Constants.KEY_SUPPORTS_OAUTH2) != null);\r
-                 boolean samlWebSsoRequired = \r
-                     (mAccountMgr.getUserData(mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null);\r
+                 boolean samlWebSsoRequired = ( \r
+                     mAccountMgr.getUserData(\r
+                         mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO\r
+                     ) != null\r
+                 );\r
                  mAuthTokenType = chooseAuthTokenType(oAuthRequired, samlWebSsoRequired);\r
                  \r
              } else {\r
                  boolean oAuthSupported = AUTH_ON.equals(getString(R.string.auth_method_oauth2));\r
-                 boolean samlWebSsoSupported = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso));\r
+                 boolean samlWebSsoSupported = \r
+                         AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso));\r
                  mAuthTokenType = chooseAuthTokenType(oAuthSupported, samlWebSsoSupported);\r
              }\r
          }\r
          if (savedInstanceState == null) {\r
              if (mAccount != null) {\r
                  mServerInfo.mBaseUrl = mAccountMgr.getUserData(mAccount, Constants.KEY_OC_BASE_URL);\r
-                 mServerInfo.mIsSslConn = mServerInfo.mBaseUrl.startsWith("https://");   // TODO do this in a setter for mBaseUrl\r
+                 // TODO do next in a setter for mBaseUrl\r
+                 mServerInfo.mIsSslConn = mServerInfo.mBaseUrl.startsWith("https://");   \r
                  String ocVersion = mAccountMgr.getUserData(mAccount, Constants.KEY_OC_VERSION);\r
                  if (ocVersion != null) {\r
                      mServerInfo.mVersion = new OwnCloudVersion(ocVersion);\r
          \r
          /// step 2 - set properties of UI elements (text, visibility, enabled...)\r
          mHostUrlInput = (EditText) findViewById(R.id.hostUrlInput);\r
 -        mHostUrlInput.setText(mServerInfo.mBaseUrl);\r
 +        // Convert IDN to Unicode\r
 +        mHostUrlInput.setText(DisplayUtils.convertIdn(mServerInfo.mBaseUrl, false));\r
          if (mAction != ACTION_CREATE) {\r
              /// lock things that should not change\r
              mHostUrlInput.setEnabled(false);\r
              @Override\r
              public boolean onTouch(View view, MotionEvent event) {\r
                  if (event.getAction() == MotionEvent.ACTION_DOWN) {\r
-                     if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType) &&\r
-                             mHostUrlInput.hasFocus()) {\r
+                     if (\r
+                             AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(\r
+                                     MainApp.getAccountType()\r
+                                     ).equals(mAuthTokenType) &&\r
+                             mHostUrlInput.hasFocus()\r
+                     ) {\r
                          checkOcServer();\r
                      }\r
                  }\r
      /**\r
       * Saves relevant state before {@link #onPause()}\r
       * \r
-      * Do NOT save {@link #mNewCapturedUriFromOAuth2Redirection}; it keeps a temporal flag, intended to defer the \r
-      * processing of the redirection caught in {@link #onNewIntent(Intent)} until {@link #onResume()} \r
+      * Do NOT save {@link #mNewCapturedUriFromOAuth2Redirection}; it keeps a temporal flag, \r
+      * intended to defer the processing of the redirection caught in \r
+      * {@link #onNewIntent(Intent)} until {@link #onResume()} \r
       * \r
       * See {@link #loadSavedInstanceState(Bundle)}\r
       */\r
  \r
  \r
      /**\r
-      * The redirection triggered by the OAuth authentication server as response to the GET AUTHORIZATION request\r
-      * is caught here.\r
+      * The redirection triggered by the OAuth authentication server as response to the \r
+      * GET AUTHORIZATION request is caught here.\r
       * \r
-      * To make this possible, this activity needs to be qualified with android:launchMode = "singleTask" in the\r
-      * AndroidManifest.xml file.\r
+      * To make this possible, this activity needs to be qualified with android:launchMode = \r
+      * "singleTask" in the AndroidManifest.xml file.\r
       */\r
      @Override\r
      protected void onNewIntent (Intent intent) {\r
  \r
  \r
      /**\r
-      * The redirection triggered by the OAuth authentication server as response to the GET AUTHORIZATION, and \r
-      * deferred in {@link #onNewIntent(Intent)}, is processed here.\r
+      * The redirection triggered by the OAuth authentication server as response to the \r
+      * GET AUTHORIZATION, and deferred in {@link #onNewIntent(Intent)}, is processed here.\r
       */\r
      @Override\r
      protected void onResume() {\r
          showRefreshButton(false);\r
          \r
          if (uri.length() != 0) {\r
 +            // Handle internationalized domain names\r
 +            uri = DisplayUtils.convertIdn(uri, true);\r
              mServerStatusText = R.string.auth_testing_connection;\r
              mServerStatusIcon = R.drawable.progress_small;\r
              showServerStatus();\r
              \r
              Intent getServerInfoIntent = new Intent();\r
              getServerInfoIntent.setAction(OperationsService.ACTION_GET_SERVER_INFO);\r
-             getServerInfoIntent.putExtra(OperationsService.EXTRA_SERVER_URL, uri);\r
+             getServerInfoIntent.putExtra(\r
+                 OperationsService.EXTRA_SERVER_URL, \r
+                 normalizeUrlSuffix(uri)\r
+             );\r
              if (mOperationsServiceBinder != null) {\r
                  mWaitingForOpId = mOperationsServiceBinder.newOperation(getServerInfoIntent);\r
              } else {\r
      }\r
  \r
      private boolean isPasswordVisible() {\r
-         return ((mPasswordInput.getInputType() & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);\r
+         return ((mPasswordInput.getInputType() & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == \r
+                 InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);\r
      }\r
  \r
      private void hidePasswordButton() {\r
      }\r
  \r
      private void showPassword() {\r
-         mPasswordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);\r
+         mPasswordInput.setInputType(\r
+                 InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD\r
+         );\r
          showViewPasswordButton();\r
      }\r
  \r
      private void hidePassword() {\r
-         mPasswordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);\r
+         mPasswordInput.setInputType(\r
+                 InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD\r
+         );\r
          showViewPasswordButton();\r
      }\r
  \r
              return;\r
          }\r
  \r
-         if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).equals(mAuthTokenType)) {\r
+         if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).\r
+                 equals(mAuthTokenType)) {\r
+             \r
              startOauthorization();\r
-         } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType)) { \r
+         } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).\r
+                 equals(mAuthTokenType)) {\r
+             \r
              startSamlBasedFederatedSingleSignOnAuthorization();\r
          } else {\r
              checkBasicAuthorization();\r
          // GET AUTHORIZATION request\r
          Uri uri = Uri.parse(mOAuthAuthEndpointText.getText().toString().trim());\r
          Uri.Builder uriBuilder = uri.buildUpon();\r
-         uriBuilder.appendQueryParameter(OAuth2Constants.KEY_RESPONSE_TYPE, getString(R.string.oauth2_response_type));\r
-         uriBuilder.appendQueryParameter(OAuth2Constants.KEY_REDIRECT_URI, getString(R.string.oauth2_redirect_uri));   \r
-         uriBuilder.appendQueryParameter(OAuth2Constants.KEY_CLIENT_ID, getString(R.string.oauth2_client_id));\r
-         uriBuilder.appendQueryParameter(OAuth2Constants.KEY_SCOPE, getString(R.string.oauth2_scope));\r
+         uriBuilder.appendQueryParameter(\r
+                 OAuth2Constants.KEY_RESPONSE_TYPE, getString(R.string.oauth2_response_type)\r
+         );\r
+         uriBuilder.appendQueryParameter(\r
+                 OAuth2Constants.KEY_REDIRECT_URI, getString(R.string.oauth2_redirect_uri)\r
+         );   \r
+         uriBuilder.appendQueryParameter(\r
+                 OAuth2Constants.KEY_CLIENT_ID, getString(R.string.oauth2_client_id)\r
+         );\r
+         uriBuilder.appendQueryParameter(\r
+                 OAuth2Constants.KEY_SCOPE, getString(R.string.oauth2_scope)\r
+         );\r
          uri = uriBuilder.build();\r
          Log_OC.d(TAG, "Starting browser to view " + uri.toString());\r
          Intent i = new Intent(Intent.ACTION_VIEW, uri);\r
  \r
          } else if (operation instanceof ExistenceCheckRemoteOperation)  {\r
              //Log_OC.wtf(TAG, "received detection response through callback" );\r
-             if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType)) {\r
+             if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).\r
+                     equals(mAuthTokenType)) {\r
                  onSamlBasedFederatedSingleSignOnAuthorizationStart(result);\r
  \r
              } else {\r
                      url = "http://" + url;\r
                  }\r
              }\r
-             \r
-             url = trimUrlWebdav(url);\r
\r
-             if (url.endsWith("/")) {\r
-                 url = url.substring(0, url.length() - 1);\r
-             }\r
\r
+         \r
+             url = normalizeUrlSuffix(url);\r
          }\r
          return (url != null ? url : "");\r
      }\r
+     \r
+     \r
+     private String normalizeUrlSuffix(String url) {\r
+         if (url.endsWith("/")) {\r
+             url = url.substring(0, url.length() - 1);\r
+         }\r
+         url = trimUrlWebdav(url);\r
+         return url;\r
+     }\r
  \r
  \r
      // TODO remove, if possible\r
              @SuppressWarnings("unchecked")\r
              Map<String, String> tokens = (Map<String, String>)(result.getData().get(0));\r
              mAuthToken = tokens.get(OAuth2Constants.KEY_ACCESS_TOKEN);\r
-             //mAuthToken = ((OAuth2GetAccessToken)operation).getResultTokenMap().get(OAuth2Constants.KEY_ACCESS_TOKEN);\r
              Log_OC.d(TAG, "Got ACCESS TOKEN: " + mAuthToken);\r
              \r
              accessRootFolderRemoteOperation("", "");\r
              showRefreshButton(true);\r
              mOkButton.setEnabled(false);\r
  \r
-             // very special case (TODO: move to a common place for all the remote operations) (dangerous here?)\r
+             // very special case (TODO: move to a common place for all the remote operations)\r
              if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {\r
                  showUntrustedCertDialog(result);\r
              }\r
  \r
  \r
      /**\r
-      * Sets the proper response to get that the Account Authenticator that started this activity saves \r
-      * a new authorization token for mAccount.\r
+      * Sets the proper response to get that the Account Authenticator that started this activity \r
+      * saves a new authorization token for mAccount.\r
       */\r
      private void updateToken() {\r
          Bundle response = new Bundle();\r
          response.putString(AccountManager.KEY_ACCOUNT_NAME, mAccount.name);\r
          response.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccount.type);\r
  \r
-         if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).equals(mAuthTokenType)) { \r
+         if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).\r
+                 equals(mAuthTokenType)) { \r
              response.putString(AccountManager.KEY_AUTHTOKEN, mAuthToken);\r
-             // the next line is necessary; by now, notifications are calling directly to the AuthenticatorActivity to update, without AccountManager intervention\r
+             // the next line is necessary, notifications are calling directly to the \r
+             // AuthenticatorActivity to update, without AccountManager intervention\r
              mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);\r
  \r
-         } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType)) {\r
+         } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).\r
+                 equals(mAuthTokenType)) {\r
  \r
              response.putString(AccountManager.KEY_AUTHTOKEN, mAuthToken);\r
-             // the next line is necessary; by now, notifications are calling directly to the AuthenticatorActivity to update, without AccountManager intervention\r
+             // the next line is necessary; by now, notifications are calling directly to the \r
+             // AuthenticatorActivity to update, without AccountManager intervention\r
              mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);\r
  \r
          } else {\r
       */\r
      private boolean createAccount() {\r
          /// create and save new ownCloud account\r
-         boolean isOAuth = AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).equals(mAuthTokenType);\r
-         boolean isSaml =  AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType);\r
+         boolean isOAuth = AccountTypeUtils.\r
+                 getAuthTokenTypeAccessToken(MainApp.getAccountType()).equals(mAuthTokenType);\r
+         boolean isSaml =  AccountTypeUtils.\r
+                 getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType);\r
  \r
          Uri uri = Uri.parse(mServerInfo.mBaseUrl);\r
          String username = mUsernameInput.getText().toString().trim();\r
              mAccount = newAccount;\r
              \r
              if (isOAuth || isSaml) {\r
-                 mAccountMgr.addAccountExplicitly(mAccount, "", null);  // with external authorizations, the password is never input in the app\r
+                 // with external authorizations, the password is never input in the app\r
+                 mAccountMgr.addAccountExplicitly(mAccount, "", null);  \r
              } else {\r
-                 mAccountMgr.addAccountExplicitly(mAccount, mPasswordInput.getText().toString(), null);\r
+                 mAccountMgr.addAccountExplicitly(\r
+                         mAccount, mPasswordInput.getText().toString(), null\r
+                 );\r
              }\r
  \r
              /// add the new account as default in preferences, if there is none already\r
              }\r
  \r
              /// prepare result to return to the Authenticator\r
-             //  TODO check again what the Authenticator makes with it; probably has the same effect as addAccountExplicitly, but it's not well done\r
+             //  TODO check again what the Authenticator makes with it; probably has the same \r
+             //  effect as addAccountExplicitly, but it's not well done\r
              final Intent intent = new Intent();       \r
              intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE,    MainApp.getAccountType());\r
              intent.putExtra(AccountManager.KEY_ACCOUNT_NAME,    mAccount.name);\r
              if (isOAuth || isSaml) {\r
                  mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);\r
              }\r
-             /// add user data to the new account; TODO probably can be done in the last parameter addAccountExplicitly, or in KEY_USERDATA
-             mAccountMgr.setUserData(mAccount, Constants.KEY_OC_VERSION,    mServerInfo.mVersion.getVersion());\r
-             mAccountMgr.setUserData(mAccount, Constants.KEY_OC_BASE_URL,   mServerInfo.mBaseUrl);\r
+             /// add user data to the new account; TODO probably can be done in the last parameter \r
+             //      addAccountExplicitly, or in KEY_USERDATA
+             mAccountMgr.setUserData(\r
+                     mAccount, Constants.KEY_OC_VERSION,    mServerInfo.mVersion.getVersion()\r
+             );\r
+             mAccountMgr.setUserData(\r
+                     mAccount, Constants.KEY_OC_BASE_URL,   mServerInfo.mBaseUrl\r
+             );\r
  
              if (isSaml) {\r
                  mAccountMgr.setUserData(mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO, "TRUE"); \r
       * @param view      'Account register' button\r
       */\r
      public void onRegisterClick(View view) {\r
-         Intent register = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.welcome_link_url)));\r
+         Intent register = new Intent(\r
+                 Intent.ACTION_VIEW, Uri.parse(getString(R.string.welcome_link_url))\r
+         );\r
          setResult(RESULT_CANCELED);\r
          startActivity(register);\r
      }\r
      /**\r
       *  Called when the 'action' button in an IME is pressed ('enter' in software keyboard).\r
       * \r
-      *  Used to trigger the authentication check when the user presses 'enter' after writing the password, \r
-      *  or to throw the server test when the only field on screen is the URL input field.\r
+      *  Used to trigger the authentication check when the user presses 'enter' after writing the \r
+      *  password, or to throw the server test when the only field on screen is the URL input field.\r
       */\r
      @Override\r
      public boolean onEditorAction(TextView inputField, int actionId, KeyEvent event) {\r
-         if (actionId == EditorInfo.IME_ACTION_DONE && inputField != null && inputField.equals(mPasswordInput)) {\r
+         if (actionId == EditorInfo.IME_ACTION_DONE && inputField != null && \r
+                 inputField.equals(mPasswordInput)) {\r
              if (mOkButton.isEnabled()) {\r
                  mOkButton.performClick();\r
              }\r
  \r
-         } else if (actionId == EditorInfo.IME_ACTION_NEXT && inputField != null && inputField.equals(mHostUrlInput)) {\r
-             if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType)) {\r
+         } else if (actionId == EditorInfo.IME_ACTION_NEXT && inputField != null && \r
+                 inputField.equals(mHostUrlInput)) {\r
+             if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).\r
+                     equals(mAuthTokenType)) {\r
                  checkOcServer();\r
              }\r
          }\r
                  final int x = (int) event.getX();\r
                  final int y = (int) event.getY();\r
                  final Rect bounds = rightDrawable.getBounds();\r
-                 if (x >= (view.getRight() - bounds.width() - fuzz) && x <= (view.getRight() - view.getPaddingRight() + fuzz)\r
-                         && y >= (view.getPaddingTop() - fuzz) && y <= (view.getHeight() - view.getPaddingBottom()) + fuzz) {\r
+                 if (    x >= (view.getRight() - bounds.width() - fuzz) && \r
+                         x <= (view.getRight() - view.getPaddingRight() + fuzz) && \r
+                         y >= (view.getPaddingTop() - fuzz) &&\r
+                         y <= (view.getHeight() - view.getPaddingBottom()) + fuzz) {\r
  \r
                      return onDrawableTouch(event);\r
                  }\r
  \r
      @Override\r
      public boolean onTouchEvent(MotionEvent event) {\r
-         if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType) &&\r
+         if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).\r
+                 equals(mAuthTokenType) &&\r
                  mHostUrlInput.hasFocus() && event.getAction() == MotionEvent.ACTION_DOWN) {\r
              checkOcServer();\r
          }\r
      /**\r
       * Show untrusted cert dialog \r
       */\r
-     public void showUntrustedCertDialog(X509Certificate x509Certificate, SslError error, SslErrorHandler handler) {\r
+     public void showUntrustedCertDialog(\r
+             X509Certificate x509Certificate, SslError error, SslErrorHandler handler\r
+         ) {\r
          // Show a dialog with the certificate info\r
          SslUntrustedCertDialog dialog = null;\r
          if (x509Certificate == null) {\r
              dialog = SslUntrustedCertDialog.newInstanceForEmptySslError(error, handler);\r
          } else {\r
-             dialog = SslUntrustedCertDialog.newInstanceForFullSslError(x509Certificate, error, handler);\r
+             dialog = SslUntrustedCertDialog.\r
+                     newInstanceForFullSslError(x509Certificate, error, handler);\r
          }\r
          FragmentManager fm = getSupportFragmentManager();\r
          FragmentTransaction ft = fm.beginTransaction();\r
       */\r
      private void showUntrustedCertDialog(RemoteOperationResult result) {\r
          // Show a dialog with the certificate info\r
-         SslUntrustedCertDialog dialog = SslUntrustedCertDialog.newInstanceForFullSslError((CertificateCombinedException)result.getException());\r
+         SslUntrustedCertDialog dialog = SslUntrustedCertDialog.\r
+                 newInstanceForFullSslError((CertificateCombinedException)result.getException());\r
          FragmentManager fm = getSupportFragmentManager();\r
          FragmentTransaction ft = fm.beginTransaction();\r
          ft.addToBackStack(null);\r
      public void onSavedCertificate() {\r
          Fragment fd = getSupportFragmentManager().findFragmentByTag(SAML_DIALOG_TAG);\r
          if (fd == null) {\r
-             // if SAML dialog is not shown, the SslDialog was shown due to an SSL error in the server check\r
+             // if SAML dialog is not shown, \r
+             // the SslDialog was shown due to an SSL error in the server check\r
              checkOcServer();\r
          }\r
      }\r
  \r
          @Override\r
          public void onServiceConnected(ComponentName component, IBinder service) {\r
-             if (component.equals(new ComponentName(AuthenticatorActivity.this, OperationsService.class))) {\r
+             if (component.equals(\r
+                     new ComponentName(AuthenticatorActivity.this, OperationsService.class)\r
+                 )) {\r
                  //Log_OC.wtf(TAG, "Operations service connected");\r
                  mOperationsServiceBinder = (OperationsServiceBinder) service;\r
                  \r
  \r
          @Override\r
          public void onServiceDisconnected(ComponentName component) {\r
-             if (component.equals(new ComponentName(AuthenticatorActivity.this, OperationsService.class))) {\r
+             if (component.equals(\r
+                     new ComponentName(AuthenticatorActivity.this, OperationsService.class)\r
+                 )) {\r
                  Log_OC.e(TAG, "Operations service crashed");\r
                  mOperationsServiceBinder = null;\r
              }\r
      public void createAuthenticationDialog(WebView webView, HttpAuthHandler handler) {\r
  \r
          // Show a dialog with the certificate info\r
-         CredentialsDialogFragment dialog = CredentialsDialogFragment.newInstanceForCredentials(webView, handler);\r
+         CredentialsDialogFragment dialog = \r
+                 CredentialsDialogFragment.newInstanceForCredentials(webView, handler);\r
          FragmentManager fm = getSupportFragmentManager();\r
          FragmentTransaction ft = fm.beginTransaction();\r
          ft.addToBackStack(null);\r
          dialog.show(ft, CREDENTIALS_DIALOG_TAG);\r
  \r
          if (!mIsFirstAuthAttempt) {\r
-             Toast.makeText(getApplicationContext(), getText(R.string.saml_authentication_wrong_pass), Toast.LENGTH_LONG).show();\r
+             Toast.makeText(\r
+                     getApplicationContext(), \r
+                     getText(R.string.saml_authentication_wrong_pass), \r
+                     Toast.LENGTH_LONG\r
+             ).show();\r
          } else {\r
              mIsFirstAuthAttempt = false;\r
          }\r
@@@ -74,6 -74,7 +74,7 @@@ public class Preferences extends Sherlo
      private final Handler mHandler = new Handler();
      private String mAccountName;
      private boolean mShowContextMenu = false;
+     private String mUploadPath;
  
  
      @SuppressWarnings("deprecation")
@@@ -87,7 -88,9 +88,9 @@@
          actionBar.setIcon(DisplayUtils.getSeasonalIconId());
          actionBar.setDisplayHomeAsUpEnabled(true);
          actionBar.setTitle(R.string.actionbar_settings);
-         
+         loadInstantUploadPath();
          // Load the accounts category for adding the list of accounts
          mAccountsPrefCategory = (PreferenceCategory) findPreference("accounts_category");
  
  
                  if (obj != null && obj instanceof LongClickableCheckBoxPreference) {
                      mShowContextMenu = true;
 -                    mAccountName = obj.toString();
 +                    mAccountName = ((LongClickableCheckBoxPreference) obj).getKey();
  
                      Preferences.this.openContextMenu(listView);
  
                  preferenceCategory.removePreference(pImprint);
              }
          }
+         Preference pInstantUploadPathApp = (Preference) findPreference("instant_upload_path");
+         pInstantUploadPathApp.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+             @Override
+             public boolean onPreferenceChange(Preference preference, Object newValue) {
+                 mUploadPath = updateInstantUploadPath(newValue.toString());
+                 return true;
+             }
+         });
              
          /* About App */
         pAboutApp = (Preference) findPreference("about_app");
      }
  
      @Override
+     protected void onPause() {
+         saveInstantUploadPathOnPreferences();
+         super.onPause();
+     }
+     @Override
      public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
  
          // Filter for only showing contextual menu when long press on the
              for (Account a : accounts) {
                  LongClickableCheckBoxPreference accountPreference = new LongClickableCheckBoxPreference(this);
                  accountPreference.setKey(a.name);
 -                accountPreference.setTitle(a.name);
 +                // Handle internationalized domain names
 +                accountPreference.setTitle(DisplayUtils.convertIdn(a.name, false));
                  mAccountsPrefCategory.addPreference(accountPreference);
  
                  // Check the current account that is being used
  
      }
  
+     /**
+      * Update the upload path checking that it is a correct path
+      * @param uploadPath: path write by user
+      * @return String: uploadPath
+      */
+     private String updateInstantUploadPath(String uploadPath) {
+         String slashString = "/";
+         // If slashes are duplicated, replace them for only one slash
+         uploadPath = uploadPath.replaceAll("/+", slashString);
+         // Remove last slash from path
+         if (uploadPath.length() > 0 && uploadPath.charAt(uploadPath.length()-1) == slashString.charAt(0)) {
+             uploadPath = uploadPath.substring(0, uploadPath.length()-1);
+         }
+         if (uploadPath.isEmpty()) { // Set default instant upload path
+             uploadPath = getString(R.string.instant_upload_path);
+         }else {
+             if (!uploadPath.startsWith(slashString)) { // Add initial slash on path if necessary
+                 uploadPath = slashString.concat(uploadPath);
+             }
+         }
+         return uploadPath;
+     }
+     /**
+      * Load upload path set on preferences
+      */
+     private void loadInstantUploadPath() {
+         SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+         mUploadPath = appPrefs.getString("instant_upload_path", getString(R.string.instant_upload_path));
+     }
+     /**
+      * Save the "Instant Upload Path" on preferences
+      */
+     private void saveInstantUploadPathOnPreferences() {
+         SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());        
+         SharedPreferences.Editor editor = appPrefs.edit();
+         editor.putString("instant_upload_path", mUploadPath);
+         editor.commit();
+     }
  }