Merge tag 'oc-android-1-3-22' into oauth_login
authorDavid A. Velasco <dvelasco@solidgear.es>
Mon, 18 Mar 2013 13:28:49 +0000 (14:28 +0100)
committerDavid A. Velasco <dvelasco@solidgear.es>
Mon, 18 Mar 2013 13:28:49 +0000 (14:28 +0100)
Conflicts:
AndroidManifest.xml
src/com/owncloud/android/authenticator/AuthenticationRunnable.java
src/com/owncloud/android/authenticator/OnAuthenticationResultListener.java
src/com/owncloud/android/authenticator/OnConnectCheckListener.java
src/com/owncloud/android/files/services/FileOperation.java
src/com/owncloud/android/files/services/InstantUploadService.java
src/com/owncloud/android/ui/activity/AuthenticatorActivity.java

25 files changed:
1  2 
AndroidManifest.xml
res/layout-land/account_setup.xml
res/layout/account_setup.xml
res/values/strings.xml
res/values/styles.xml
src/com/owncloud/android/AccountUtils.java
src/com/owncloud/android/Uploader.java
src/com/owncloud/android/authenticator/AccountAuthenticator.java
src/com/owncloud/android/files/OwnCloudFileObserver.java
src/com/owncloud/android/files/services/FileDownloader.java
src/com/owncloud/android/files/services/FileUploader.java
src/com/owncloud/android/network/OwnCloudClientUtils.java
src/com/owncloud/android/operations/OwnCloudServerCheckOperation.java
src/com/owncloud/android/operations/RemoteOperation.java
src/com/owncloud/android/operations/RemoteOperationResult.java
src/com/owncloud/android/operations/RenameFileOperation.java
src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java
src/com/owncloud/android/syncadapter/FileSyncAdapter.java
src/com/owncloud/android/ui/activity/AccountSelectActivity.java
src/com/owncloud/android/ui/activity/AuthenticatorActivity.java
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/activity/LandingActivity.java
src/com/owncloud/android/ui/fragment/FileDetailFragment.java
src/com/owncloud/android/ui/fragment/OCFileListFragment.java
src/eu/alefzero/webdav/WebdavClient.java

diff --combined AndroidManifest.xml
@@@ -3,9 -3,11 +3,11 @@@
    ownCloud Android client application\r
  \r
    Copyright (C) 2012  Bartek Przybylski\r
+   Copyright (C) 2012-2013 ownCloud Inc.\r
\r
    This program is free software: you can redistribute it and/or modify\r
    it under the terms of the GNU General Public License as published by\r
-   the Free Software Foundation, either version 3 of the License, or\r
+   the Free Software Foundation, either version 2 of the License, or\r
    (at your option) any later version.\r
  \r
    This program is distributed in the hope that it will be useful,\r
@@@ -17,8 -19,8 +19,8 @@@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
   -->\r
  <manifest package="com.owncloud.android"\r
-     android:versionCode="103018"\r
-     android:versionName="1.3.18" xmlns:android="http://schemas.android.com/apk/res/android">\r
+     android:versionCode="103022"\r
+     android:versionName="1.3.22" xmlns:android="http://schemas.android.com/apk/res/android">\r
  \r
      <uses-permission android:name="android.permission.GET_ACCOUNTS" />\r
      <uses-permission android:name="android.permission.USE_CREDENTIALS" />\r
          <activity\r
              android:name=".ui.activity.AuthenticatorActivity"\r
              android:exported="true"\r
 -            android:theme="@style/Theme.ownCloud.noActionBar" >\r
 +            android:theme="@style/Theme.ownCloud.noActionBar" \r
 +            android:launchMode="singleTask">\r
 +            <intent-filter>\r
 +                <action android:name="android.intent.action.VIEW" />\r
\r
 +                <category android:name="android.intent.category.DEFAULT" />\r
 +                <category android:name="android.intent.category.BROWSABLE" />\r
\r
 +                <data android:scheme="oauth-mobile-app" />\r
 +            </intent-filter>\r
+             <intent-filter>\r
+                 <action android:name="com.owncloud.android.workaround.accounts.CREATE" />\r
+                 <category android:name="android.intent.category.DEFAULT" />\r
+             </intent-filter>\r
          </activity>\r
  \r
          <service android:name=".files.services.FileDownloader" >\r
          
          <service android:name=".files.services.FileUploader" >\r
          </service>
 -        <service android:name=".files.services.InstantUploadService" />
          <receiver android:name=".files.InstantUploadBroadcastReceiver">\r
              <intent-filter>\r
                  <action android:name="com.android.camera.NEW_PICTURE" />\r
                  <action android:name="android.intent.action.BOOT_COMPLETED"/>\r
              </intent-filter>\r
          </receiver>\r
 -        <service android:name=".files.services.FileObserverService"/>
 +        <service android:name=".files.services.FileObserverService"/>\r
 +        \r
 +        <service android:name=".authenticator.oauth2.services.OAuth2GetTokenService" >\r
 +        </service>\r
 +        
      </application>\r
  \r
  </manifest>
@@@ -2,10 -2,12 +2,12 @@@
  <!--
    ownCloud Android client application\r
  \r
-   Copyright (C) 2012  Bartek Przybylski\r
+   Copyright (C) 2012  Bartek Przybylski
+   Copyright (C) 2012-2013 ownCloud Inc.
\r
    This program is free software: you can redistribute it and/or modify\r
    it under the terms of the GNU General Public License as published by\r
-   the Free Software Foundation, either version 3 of the License, or\r
+   the Free Software Foundation, either version 2 of the License, or\r
    (at your option) any later version.\r
  \r
    This program is distributed in the hope that it will be useful,\r
                      android:layout_weight="1" >
  
                      <EditText
 -                        android:id="@+id/host_URL"
 +                        android:id="@+id/hostUrlInput"
                          android:layout_width="match_parent"
                          android:layout_height="wrap_content"
 -                        android:layout_weight="1"
                          android:ems="10"
                          android:hint="@string/auth_host_url"
                          android:inputType="textNoSuggestions">
@@@ -73,7 -76,6 +75,7 @@@
                          android:layout_height="wrap_content"
                          android:layout_gravity="right|center_vertical"
                          android:src="@drawable/ic_action_refresh_black"
 +                      android:onClick="onRefreshClick"
                          android:visibility="invisible" />
                  </FrameLayout>
  
                          android:visibility="invisible" />
                  </LinearLayout>
  
 +                <CheckBox
 +                    android:id="@+id/oauth_onOff_check"
 +                    android:layout_width="wrap_content"
 +                    android:layout_height="wrap_content"
 +                    android:checked="false"
 +                    android:onClick="onCheckClick"
 +                    android:text="@string/oauth_check_onoff"
 +                    android:textAppearance="?android:attr/textAppearanceSmall" />
 +
                  <TextView
                      android:id="@+id/textView2"
                      android:layout_width="wrap_content"
                      android:text="@string/auth_login_details"
                      android:textAppearance="?android:attr/textAppearanceSmall" />
  
 +                  <EditText
 +                      android:id="@+id/oAuthEntryPoint_1"
 +                      android:layout_width="match_parent"
 +                      android:layout_height="wrap_content"
 +                      android:layout_weight="1"
 +                      android:ems="10"
 +                      android:enabled="false"
 +                      android:text="@string/oauth_url_endpoint_auth"
 +                      android:singleLine="true"
 +                      android:visibility="gone" >
 +      
 +                      <requestFocus />
 +                  </EditText>            
 +      
 +                  <EditText
 +                      android:id="@+id/oAuthEntryPoint_2"
 +                      android:layout_width="match_parent"
 +                      android:layout_height="wrap_content"
 +                      android:layout_weight="1"
 +                      android:ems="10"
 +                      android:enabled="false"
 +                      android:text="@string/oauth_url_endpoint_access"
 +                      android:singleLine="true"
 +                      android:visibility="gone" >
 +      
 +                      <requestFocus />
 +                  </EditText>            
 +      
                  <EditText
                      android:id="@+id/account_username"
                      android:layout_width="match_parent"
                          android:id="@+id/account_password"
                          android:layout_width="match_parent"
                          android:layout_height="wrap_content"
 -                        android:layout_weight="1"
                          android:ems="10"
                          android:hint="@string/auth_password"
                          android:inputType="textPassword"/>
  
                      <ImageView
 -                        android:id="@+id/viewPassword"
 +                        android:id="@+id/viewPasswordButton"
                          android:layout_width="wrap_content"
                          android:layout_height="wrap_content"
                          android:layout_gravity="right|center_vertical"
                          android:src="@android:drawable/ic_menu_view"
 +                                              android:onClick="onViewPasswordClick"
                          android:visibility="invisible" />
                  </FrameLayout>
              </LinearLayout>
 +            
 +            <!-- LinearLayout
 +                android:id="@+id/auth_status_layout"
 +                android:layout_width="match_parent"
 +                android:layout_height="wrap_content"
 +                android:layout_weight="1"
 +                android:visibility="invisible" 
 +                >
 +
 +                <ImageView
 +                    android:id="@+id/auth_status_icon"
 +                    android:layout_width="wrap_content"
 +                    android:layout_height="wrap_content"
 +                    android:layout_marginLeft="5dp"
 +                    android:layout_marginRight="5dp"
 +                    android:src="@android:drawable/stat_notify_sync"
 +                    />
 +
 +                <TextView
 +                    android:id="@+id/auth_status_text"
 +                    android:layout_width="wrap_content"
 +                    android:layout_height="wrap_content"
 +                    android:text="@string/text_placeholder"
 +                    />
 +                
 +            </LinearLayout -->
 +                
 +            <TextView
 +                android:id="@+id/auth_status_text"
 +                android:layout_width="match_parent"
 +                android:layout_height="wrap_content"
 +                android:layout_weight="1" 
 +                android:text="@string/text_placeholder"
 +                android:layout_marginLeft="5dp"
 +                android:layout_marginRight="5dp"
 +                              android:drawableLeft="@android:drawable/stat_notify_sync"
 +                      android:drawablePadding="5dip"
 +                      android:visibility="invisible"                
 +                />
 +                    
 +            
          </LinearLayout>
      </FrameLayout>
  
@@@ -2,10 -2,12 +2,12 @@@
  <!--
    ownCloud Android client application\r
  \r
-   Copyright (C) 2012  Bartek Przybylski\r
+   Copyright (C) 2012  Bartek Przybylski
+   Copyright (C) 2012-2013 ownCloud Inc.
\r
    This program is free software: you can redistribute it and/or modify\r
    it under the terms of the GNU General Public License as published by\r
-   the Free Software Foundation, either version 3 of the License, or\r
+   the Free Software Foundation, either version 2 of the License, or\r
    (at your option) any later version.\r
  \r
    This program is distributed in the hope that it will be useful,\r
@@@ -36,6 -38,7 +38,6 @@@
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_gravity="center"
 -            android:layout_weight="1"
              android:orientation="vertical" >
  
              <ImageView
                  android:layout_weight="1" >
  
                  <EditText
 -                    android:id="@+id/host_URL"
 +                    android:id="@+id/hostUrlInput"
                      android:layout_width="match_parent"
                      android:layout_height="wrap_content"
 -                    android:layout_weight="1"
                      android:ems="10"
                      android:hint="@string/auth_host_url"
                      android:inputType="textNoSuggestions" >
@@@ -66,7 -70,6 +68,7 @@@
                      android:layout_width="wrap_content"
                      android:layout_height="wrap_content"
                      android:src="@drawable/ic_action_refresh_black"
 +                    android:onClick="onRefreshClick"
                      android:layout_gravity="right|center_vertical"
                      android:visibility="invisible" />
  
                      android:layout_height="wrap_content"
                      android:text="TextView"
                      android:visibility="invisible" />
 -
              </LinearLayout>
  
 +            <CheckBox
 +                android:id="@+id/oauth_onOff_check"
 +                android:layout_width="wrap_content"
 +                android:layout_height="wrap_content"
 +                android:checked="false"
 +                android:onClick="onCheckClick"
 +                android:text="@string/oauth_check_onoff"
 +                android:textAppearance="?android:attr/textAppearanceSmall" />
 +
              <TextView
                  android:id="@+id/textView2"
                  android:layout_width="wrap_content"
                  android:layout_weight="1"
                  android:text="@string/auth_login_details"
                  android:textAppearance="?android:attr/textAppearanceSmall" />
 +            
 +            <EditText
 +                android:id="@+id/oAuthEntryPoint_1"
 +                android:layout_width="match_parent"
 +                android:layout_height="wrap_content"
 +                android:layout_weight="1"
 +                android:ems="10"
 +                android:enabled="false"
 +                android:text="@string/oauth_url_endpoint_auth"
 +                android:singleLine="true"
 +                android:visibility="gone" >
 +
 +                <requestFocus />
 +            </EditText>            
 +
 +            <EditText
 +                android:id="@+id/oAuthEntryPoint_2"
 +                android:layout_width="match_parent"
 +                android:layout_height="wrap_content"
 +                android:layout_weight="1"
 +                android:ems="10"
 +                android:enabled="false"
 +                  android:text="@string/oauth_url_endpoint_access"
 +                android:singleLine="true"
 +                android:visibility="gone" >
 +
 +                <requestFocus />
 +            </EditText>            
  
              <EditText
                  android:id="@+id/account_username"
                      android:id="@+id/account_password"
                      android:layout_width="match_parent"
                      android:layout_height="wrap_content"
 -                    android:layout_weight="1"
                      android:ems="10"
                      android:hint="@string/auth_password"
                      android:inputType="textPassword"/>
  
                  <ImageView
 -                    android:id="@+id/viewPassword"
 +                    android:id="@+id/viewPasswordButton"
                      android:layout_width="wrap_content"
                      android:layout_height="wrap_content"
                      android:layout_gravity="right|center_vertical"
                      android:src="@android:drawable/ic_menu_view"
 +                                      android:onClick="onViewPasswordClick"
                      android:visibility="invisible" />
  
              </FrameLayout>
  
 -            </LinearLayout>
 +            <!-- LinearLayout
 +                android:id="@+id/auth_status_layout"
 +                android:layout_width="match_parent"
 +                android:layout_height="wrap_content"
 +                android:layout_weight="1" 
 +                android:visibility="invisible"
 +                >
 +
 +                <ImageView
 +                    android:id="@+id/auth_status_icon"
 +                    android:layout_width="wrap_content"
 +                    android:layout_height="wrap_content"
 +                    android:layout_marginLeft="5dp"
 +                    android:layout_marginRight="5dp"
 +                    android:src="@android:drawable/stat_notify_sync"
 +                    />
 +
 +                <TextView
 +                    android:id="@+id/auth_status_text"
 +                    android:layout_width="wrap_content"
 +                    android:layout_height="wrap_content"
 +                    android:text="@string/text_placeholder"
 +                    >
 +                
 +            </LinearLayout -->
 +            
 +            <TextView
 +                android:id="@+id/auth_status_text"
 +                android:layout_width="match_parent"
 +                android:layout_height="wrap_content"
 +                android:layout_weight="1" 
 +                android:text="@string/text_placeholder"
 +                android:layout_marginLeft="5dp"
 +                android:layout_marginRight="5dp"
 +                              android:drawableLeft="@android:drawable/stat_notify_sync"
 +                      android:drawablePadding="5dip"
 +                      android:visibility="invisible"                
 +                />
 +                    
 +              </LinearLayout>
  
      </FrameLayout>
  
diff --combined res/values/strings.xml
@@@ -25,7 -25,6 +25,6 @@@
      <string name="actionbar_settings">Settings</string>
      
      <string name="prefs_category_general">General</string>
-     <string name="prefs_category_trackmydevice">Device tracking</string>
      <string name="prefs_add_session">Add new session</string>
      <string name="prefs_create_img_thumbnails">Create image thumbnails</string>
      <string name="prefs_select_oc_account">Select an account</string>
      <string name="sync_string_contacts">Contacts</string>
        <string name="sync_fail_ticker">Synchronization failed</string>
      <string name="sync_fail_content">Synchronization of %1$s could not be completed</string>
 +    <string name="sync_fail_content_unauthorized">Invalid credentials for %1$s</string>
        <string name="sync_conflicts_in_favourites_ticker">Conflicts found</string>
        <string name="sync_conflicts_in_favourites_content">%1$d kept-in-sync files could not be sync\'ed</string>
      <string name="sync_fail_in_favourites_ticker">Kept-in-sync files failed</string>
        <string name="auth_wrong_connection_title">Couldn\'t establish connection</string>
        <string name="auth_secure_connection">Secure connection established</string>
      <string name="auth_login_details">Login details</string>
 -    <string name="auth_unauthorized">Invalid login / password</string>
 +    <string name="auth_unauthorized">Invalid credentials</string>
 +      <string name="auth_oauth_error">Unsuccessful authorization</string>
 +      <string name="auth_oauth_error_access_denied">Access denied by authorization server</string>
      <string name="auth_not_found">Wrong path given</string>
      <string name="auth_internal">Internal server error, code %1$d</string>
 +    <string name="auth_wtf_reenter_URL">Unexpected state; please, enter the server URL again</string>
 +    <string name="auth_expired_oauth_token_toast">Your authorization expired.\nPlease, authorize again</string>
 +    <string name="auth_expired_basic_auth_toast">Your saved credentials are invalid.\nPlease, enter the current credentials</string>
      
      <string name="crashlog_message">Application terminated unexpectedly. Would you like to submit a crash report?</string>
      <string name="crashlog_send_report">Send report</string>
      <string name="filedisplay_unexpected_bad_get_content">"Unexpected problem ; please select the file from a different app"</string>
      <string name="filedisplay_no_file_selected">No file was selected</string>
      
 +    <string name="oauth_host_url">oAuth2 URL</string> 
 +    <string name="oauth_check_onoff">Login with oAuth2.</string> 
 +    <string name="oauth_login_connection">Connecting to oAuth2 server…</string>    
 +    <string name="oauth_code_validation_message">Please, open a web browser and go to:\n%1$s.\nValidate this code there:\n%2$s</string>
 +    <string name="oauth_connection_url_unavailable">Connection to this URL not available.</string> 
 +        
      <string name="ssl_validator_title">Warning</string>
      <string name="ssl_validator_header">The identity of the site could not be verified</string>
      <string name="ssl_validator_reason_cert_not_trusted">- The server certificate is not trusted</string>
diff --combined res/values/styles.xml
@@@ -1,4 -1,23 +1,23 @@@
  <?xml version="1.0" encoding="utf-8"?>
+ <!--
+   ownCloud Android client application
+   Copyright (C) 2012  Bartek Przybylski
+   Copyright (C) 2012-2013 ownCloud Inc.
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 2 of the License, or
+   (at your option) any later version.
+   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/>.
+ -->
  <resources>
        <style name="Animations" />
  
                <item name="android:singleLine">true</item>
                    
      </style>
 +      
 +      <style name="OAuthDialog" parent="@android:style/Theme.Dialog">
 +              <item name="android:windowNoTitle">false</item> 
 +      </style>    
                
        <color name="setup_text_hint">#777777</color>
        <color name="setup_text_typed">#000000</color>
@@@ -1,9 -1,10 +1,10 @@@
  /* ownCloud Android client application\r
   *   Copyright (C) 2012  Bartek Przybylski\r
+  *   Copyright (C) 2012-2013 ownCloud Inc.\r
   *\r
   *   This program is free software: you can redistribute it and/or modify\r
   *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 3 of the License, or\r
+  *   the Free Software Foundation, either version 2 of the License, or\r
   *   (at your option) any later version.\r
   *\r
   *   This program is distributed in the hope that it will be useful,\r
@@@ -31,7 -32,6 +32,7 @@@ public class AccountUtils 
      public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php";\r
      public static final String WEBDAV_PATH_2_0 = "/files/webdav.php";\r
      public static final String WEBDAV_PATH_4_0 = "/remote.php/webdav";\r
 +    private static final String ODAV_PATH = "/remote.php/odav";\r
      public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php";\r
      public static final String CARDDAV_PATH_4_0 = "/remote/carddav.php";\r
      public static final String STATUS_PATH = "/status.php";\r
@@@ -61,7 -61,9 +62,9 @@@
                      break;\r
                  }\r
              }\r
-         } else if (ocAccounts.length != 0) {\r
+         }\r
+         \r
+         if (defaultAccount == null && ocAccounts.length != 0) {\r
              // we at least need to take first account as fallback\r
              defaultAccount = ocAccounts[0];\r
          }\r
      }\r
      \r
      \r
-     public static void setCurrentOwnCloudAccount(Context context, String name) {\r
-         SharedPreferences.Editor appPrefs = PreferenceManager\r
-                 .getDefaultSharedPreferences(context).edit();\r
-         appPrefs.putString("select_oc_account", name);\r
-         appPrefs.commit();\r
+     public static boolean setCurrentOwnCloudAccount(Context context, String accountName) {\r
+         boolean result = false;\r
+         if (accountName != null) {\r
+             Account[] ocAccounts = AccountManager.get(context).getAccountsByType(\r
+                     AccountAuthenticator.ACCOUNT_TYPE);\r
+             boolean found = false;\r
+             for (Account account : ocAccounts) {\r
+                 found = (account.name.equals(accountName));\r
+                 if (found) {\r
+                     SharedPreferences.Editor appPrefs = PreferenceManager\r
+                             .getDefaultSharedPreferences(context).edit();\r
+                     appPrefs.putString("select_oc_account", accountName);\r
+     \r
+                     appPrefs.commit();\r
+                     result = true;\r
+                     break;\r
+                 }\r
+             }\r
+         }\r
+         return result;\r
      }\r
  \r
      /**\r
       * @param version version of owncloud\r
       * @return webdav path for given OC version, null if OC version unknown\r
       */\r
 -    public static String getWebdavPath(OwnCloudVersion version) {\r
 +    public static String getWebdavPath(OwnCloudVersion version, boolean supportsOAuth) {\r
          if (version != null) {\r
 +            if (supportsOAuth) {\r
 +                return ODAV_PATH;\r
 +            }\r
              if (version.compareTo(OwnCloudVersion.owncloud_v4) >= 0)\r
                  return WEBDAV_PATH_4_0;\r
              if (version.compareTo(OwnCloudVersion.owncloud_v3) >= 0\r
              AccountManager ama = AccountManager.get(context);\r
              String baseurl = ama.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL);\r
              String strver  = ama.getUserData(account, AccountAuthenticator.KEY_OC_VERSION);\r
 +            boolean supportsOAuth = (ama.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null);\r
              OwnCloudVersion ver = new OwnCloudVersion(strver);\r
 -            String webdavpath = getWebdavPath(ver);\r
 +            String webdavpath = getWebdavPath(ver, supportsOAuth);\r
  \r
              if (webdavpath == null) return null;\r
              return baseurl + webdavpath;\r
@@@ -1,9 -1,10 +1,10 @@@
  /* ownCloud Android client application\r
   *   Copyright (C) 2012  Bartek Przybylski\r
+  *   Copyright (C) 2012-2013 ownCloud Inc.\r
   *\r
   *   This program is free software: you can redistribute it and/or modify\r
   *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 3 of the License, or\r
+  *   the Free Software Foundation, either version 2 of the License, or\r
   *   (at your option) any later version.\r
   *\r
   *   This program is distributed in the hope that it will be useful,\r
@@@ -30,6 -31,7 +31,6 @@@ import com.owncloud.android.datamodel.D
  import com.owncloud.android.datamodel.FileDataStorageManager;\r
  import com.owncloud.android.datamodel.OCFile;\r
  import com.owncloud.android.files.services.FileUploader;\r
 -import com.owncloud.android.network.OwnCloudClientUtils;\r
  \r
  import android.accounts.Account;\r
  import android.accounts.AccountManager;\r
@@@ -59,6 -61,7 +60,6 @@@ import android.widget.SimpleAdapter
  import android.widget.Toast;\r
  \r
  import com.owncloud.android.R;\r
 -import eu.alefzero.webdav.WebdavClient;\r
  \r
  /**\r
   * This can be used to upload things to an ownCloud instance.\r
@@@ -138,8 -141,8 +139,8 @@@ public class Uploader extends ListActiv
                          // in API7 < this constatant is defined in\r
                          // Settings.ADD_ACCOUNT_SETTINGS\r
                          // and Settings.EXTRA_AUTHORITIES\r
 -                        Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");\r
 -                        intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
 +                        Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);\r
 +                        intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTHORITY });\r
                          startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);\r
                      } else {\r
                          // since in API7 there is no direct call for\r
  \r
      public void uploadFiles() {\r
          try {\r
 +            /* TODO - mCreateDir can never be true at this moment; we will replace wdc.createDirectory by CreateFolderOperation when that is fixed \r
              WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext());\r
 -\r
              // create last directory in path if necessary\r
              if (mCreateDir) {\r
                  wdc.createDirectory(mUploadPath);\r
              }\r
 +            */\r
  \r
              String[] local = new String[mStreamsToUpload.size()], remote = new String[mStreamsToUpload.size()];\r
  \r
@@@ -1,9 -1,10 +1,10 @@@
  /* ownCloud Android client application\r
   *   Copyright (C) 2012  Bartek Przybylski\r
+  *   Copyright (C) 2012-2013 ownCloud Inc.\r
   *\r
   *   This program is free software: you can redistribute it and/or modify\r
   *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 3 of the License, or\r
+  *   the Free Software Foundation, either version 2 of the License, or\r
   *   (at your option) any later version.\r
   *\r
   *   This program is distributed in the hope that it will be useful,\r
@@@ -32,11 -33,7 +33,11 @@@ public class AccountAuthenticator exten
       * used by application and all extensions.\r
       */\r
      public static final String ACCOUNT_TYPE = "owncloud";\r
 +    public static final String AUTHORITY = "org.owncloud";\r
      public static final String AUTH_TOKEN_TYPE = "org.owncloud";\r
 +    public static final String AUTH_TOKEN_TYPE_PASSWORD = "owncloud.password";\r
 +    public static final String AUTH_TOKEN_TYPE_ACCESS_TOKEN = "owncloud.oauth2.access_token";\r
 +    public static final String AUTH_TOKEN_TYPE_REFRESH_TOKEN = "owncloud.oauth2.refresh_token";\r
  \r
      public static final String KEY_AUTH_TOKEN_TYPE = "authTokenType";\r
      public static final String KEY_REQUIRED_FEATURES = "requiredFeatures";\r
       * http://server/path or https://owncloud.server\r
       */\r
      public static final String KEY_OC_BASE_URL = "oc_base_url";\r
 -\r
 -    private static final String TAG = "AccountAuthenticator";\r
 +    /**\r
 +     * Flag signaling if the ownCloud server can be accessed with OAuth2 access tokens.\r
 +     */\r
 +    public static final String KEY_SUPPORTS_OAUTH2 = "oc_supports_oauth2";\r
 +    \r
 +    private static final String TAG = AccountAuthenticator.class.getSimpleName();\r
 +    \r
      private Context mContext;\r
  \r
      public AccountAuthenticator(Context context) {\r
              return e.getFailureBundle();\r
          }\r
          final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
 -        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
 -                response);\r
 +        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);\r
          intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
          intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures);\r
          intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
 +        intent.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_CREATE);\r
  \r
          setIntentFlags(intent);\r
 +        \r
          final Bundle bundle = new Bundle();\r
          bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
          return bundle;\r
          return null;\r
      }\r
  \r
 +    /**\r
 +     * {@inheritDoc}\r
 +     */\r
      @Override\r
      public Bundle getAuthToken(AccountAuthenticatorResponse response,\r
              Account account, String authTokenType, Bundle options)\r
              throws NetworkErrorException {\r
 +        /// validate parameters\r
          try {\r
              validateAccountType(account.type);\r
              validateAuthTokenType(authTokenType);\r
              e.printStackTrace();\r
              return e.getFailureBundle();\r
          }\r
 +        \r
 +        /// check if required token is stored\r
          final AccountManager am = AccountManager.get(mContext);\r
 -        final String password = am.getPassword(account);\r
 -        if (password != null) {\r
 +        String accessToken;\r
 +        if (authTokenType.equals(AUTH_TOKEN_TYPE_PASSWORD)) {\r
 +            accessToken = am.getPassword(account);\r
 +        } else {\r
 +            accessToken = am.peekAuthToken(account, authTokenType);\r
 +        }\r
 +        if (accessToken != null) {\r
              final Bundle result = new Bundle();\r
              result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);\r
              result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);\r
 -            result.putString(AccountManager.KEY_AUTHTOKEN, password);\r
 +            result.putString(AccountManager.KEY_AUTHTOKEN, accessToken);\r
              return result;\r
          }\r
 -\r
 +        \r
 +        /// if not stored, return Intent to access the AuthenticatorActivity and UPDATE the token for the account\r
          final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
 -        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
 -                response);\r
 +        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);\r
          intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
          intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
 -        intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name);\r
 +        intent.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, account);\r
 +        intent.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);\r
 +        \r
  \r
          final Bundle bundle = new Bundle();\r
          bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
      public Bundle hasFeatures(AccountAuthenticatorResponse response,\r
              Account account, String[] features) throws NetworkErrorException {\r
          final Bundle result = new Bundle();\r
-         result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);\r
+         result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);\r
          return result;\r
      }\r
  \r
  \r
      private void setIntentFlags(Intent intent) {\r
          intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\r
 -        intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);\r
 -        intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);\r
 +        //intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);\r
 +        //intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); // incompatible with the authorization code grant in OAuth\r
          intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);\r
          intent.addFlags(Intent.FLAG_FROM_BACKGROUND);\r
      }\r
  \r
      private void validateAuthTokenType(String authTokenType)\r
              throws UnsupportedAuthTokenTypeException {\r
 -        if (!authTokenType.equals(AUTH_TOKEN_TYPE)) {\r
 +        if (!authTokenType.equals(AUTH_TOKEN_TYPE) &&\r
 +            !authTokenType.equals(AUTH_TOKEN_TYPE_PASSWORD) &&\r
 +            !authTokenType.equals(AUTH_TOKEN_TYPE_ACCESS_TOKEN) &&\r
 +            !authTokenType.equals(AUTH_TOKEN_TYPE_REFRESH_TOKEN) ) {\r
              throw new UnsupportedAuthTokenTypeException();\r
          }\r
      }\r
@@@ -1,9 -1,10 +1,10 @@@
  /* ownCloud Android client application
   *   Copyright (C) 2012 Bartek Przybylski
+  *   Copyright (C) 2012-2013 ownCloud Inc.
   *
   *   This program is free software: you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
-  *   the Free Software Foundation, either version 3 of the License, or
+  *   the Free Software Foundation, either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
@@@ -22,11 -23,13 +23,11 @@@ import java.io.File
  
  import com.owncloud.android.datamodel.FileDataStorageManager;
  import com.owncloud.android.datamodel.OCFile;
 -import com.owncloud.android.network.OwnCloudClientUtils;
  import com.owncloud.android.operations.RemoteOperationResult;
  import com.owncloud.android.operations.SynchronizeFileOperation;
  import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
  import com.owncloud.android.ui.activity.ConflictsResolveActivity;
  
 -import eu.alefzero.webdav.WebdavClient;
  
  import android.accounts.Account;
  import android.content.Context;
@@@ -75,6 -78,7 +76,6 @@@ public class OwnCloudFileObserver exten
                           mPath);
              return;
          }
 -        WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mOCAccount, mContext);
          FileDataStorageManager storageManager = new FileDataStorageManager(mOCAccount, mContext.getContentResolver());
          OCFile file = storageManager.getFileByLocalPath(mPath);     // a fresh object is needed; many things could have occurred to the file since it was registered to observe
                                                                      // again, assuming that local files are linked to a remote file AT MOST, SOMETHING TO BE DONE; 
@@@ -85,7 -89,7 +86,7 @@@
                                                                      true, 
                                                                      true, 
                                                                      mContext);
 -        RemoteOperationResult result = sfo.execute(wc);
 +        RemoteOperationResult result = sfo.execute(mOCAccount, mContext);
          if (result.getCode() == ResultCode.SYNC_CONFLICT) {
              // ISSUE 5: if the user is not running the app (this is a service!), this can be very intrusive; a notification should be preferred
              Intent i = new Intent(mContext, ConflictsResolveActivity.class);
@@@ -1,9 -1,10 +1,10 @@@
  /* ownCloud Android client application\r
   *   Copyright (C) 2012 Bartek Przybylski\r
+  *   Copyright (C) 2012-2013 ownCloud Inc.\r
   *\r
   *   This program is free software: you can redistribute it and/or modify\r
   *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 3 of the License, or\r
+  *   the Free Software Foundation, either version 2 of the License, or\r
   *   (at your option) any later version.\r
   *\r
   *   This program is distributed in the hope that it will be useful,\r
@@@ -19,7 -20,6 +20,7 @@@
  package com.owncloud.android.files.services;\r
  \r
  import java.io.File;\r
 +import java.io.IOException;\r
  import java.util.AbstractList;\r
  import java.util.Iterator;\r
  import java.util.Vector;\r
@@@ -37,7 -37,6 +38,7 @@@ import com.owncloud.android.ui.activity
  import com.owncloud.android.ui.fragment.FileDetailFragment;\r
  \r
  import android.accounts.Account;\r
 +import android.accounts.AccountsException;\r
  import android.app.Notification;\r
  import android.app.NotificationManager;\r
  import android.app.PendingIntent;\r
@@@ -265,30 -264,21 +266,30 @@@ public class FileDownloader extends Ser
              \r
              notifyDownloadStart(mCurrentDownload);\r
  \r
 -            /// prepare client object to send the request to the ownCloud server\r
 -            if (mDownloadClient == null || !mLastAccount.equals(mCurrentDownload.getAccount())) {\r
 -                mLastAccount = mCurrentDownload.getAccount();\r
 -                mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());\r
 -                mDownloadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());\r
 -            }\r
 -\r
 -            /// perform the download\r
              RemoteOperationResult downloadResult = null;\r
              try {\r
 -                downloadResult = mCurrentDownload.execute(mDownloadClient);\r
 +                /// prepare client object to send the request to the ownCloud server\r
 +                if (mDownloadClient == null || !mLastAccount.equals(mCurrentDownload.getAccount())) {\r
 +                    mLastAccount = mCurrentDownload.getAccount();\r
 +                    mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());\r
 +                    mDownloadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());\r
 +                }\r
 +\r
 +                /// perform the download\r
 +                if (downloadResult == null) {\r
 +                    downloadResult = mCurrentDownload.execute(mDownloadClient);\r
 +                }\r
                  if (downloadResult.isSuccess()) {\r
                      saveDownloadedFile();\r
                  }\r
              \r
 +            } catch (AccountsException e) {\r
 +                Log.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);\r
 +                downloadResult = new RemoteOperationResult(e);\r
 +            } catch (IOException e) {\r
 +                Log.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);\r
 +                downloadResult = new RemoteOperationResult(e);\r
 +                \r
              } finally {\r
                  synchronized(mPendingDownloads) {\r
                      mPendingDownloads.remove(downloadKey);\r
@@@ -1,9 -1,10 +1,10 @@@
  /* ownCloud Android client application
   *   Copyright (C) 2012 Bartek Przybylski
+  *   Copyright (C) 2012-2013 ownCloud Inc.
   *
   *   This program is free software: you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
-  *   the Free Software Foundation, either version 3 of the License, or
+  *   the Free Software Foundation, either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
@@@ -19,7 -20,6 +20,7 @@@
  package com.owncloud.android.files.services;
  
  import java.io.File;
 +import java.io.IOException;
  import java.util.AbstractList;
  import java.util.Iterator;
  import java.util.Vector;
@@@ -35,8 -35,6 +36,8 @@@ import com.owncloud.android.datamodel.F
  import com.owncloud.android.datamodel.OCFile;
  import com.owncloud.android.files.InstantUploadBroadcastReceiver;
  import com.owncloud.android.operations.ChunkedUploadFileOperation;
 +import com.owncloud.android.operations.CreateFolderOperation;
 +import com.owncloud.android.operations.RemoteOperation;
  import com.owncloud.android.operations.RemoteOperationResult;
  import com.owncloud.android.operations.UploadFileOperation;
  import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
@@@ -52,7 -50,6 +53,7 @@@ import com.owncloud.android.network.Own
  
  import android.accounts.Account;
  import android.accounts.AccountManager;
 +import android.accounts.AccountsException;
  import android.app.Notification;
  import android.app.NotificationManager;
  import android.app.PendingIntent;
@@@ -396,45 -393,34 +397,45 @@@ public class FileUploader extends Servi
              
              notifyUploadStart(mCurrentUpload);
  
 +            RemoteOperationResult uploadResult = null;
              
 -            /// prepare client object to send requests to the ownCloud server
 -            if (mUploadClient == null || !mLastAccount.equals(mCurrentUpload.getAccount())) {
 -                mLastAccount = mCurrentUpload.getAccount();
 -                mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());
 -                mUploadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());
 -            }
 +            try {
 +                /// prepare client object to send requests to the ownCloud server
 +                if (mUploadClient == null || !mLastAccount.equals(mCurrentUpload.getAccount())) {
 +                    mLastAccount = mCurrentUpload.getAccount();
 +                    mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());
 +                    mUploadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());
 +                }
              
 -            /// create remote folder for instant uploads
 -            if (mCurrentUpload.isRemoteFolderToBeCreated()) {
 -                mUploadClient.createDirectory(InstantUploadBroadcastReceiver.INSTANT_UPLOAD_DIR);    // ignoring result; fail could just mean that it already exists, but local database is not synchronized; the upload will be tried anyway
 -            }
 +                /// create remote folder for instant uploads
 +                if (mCurrentUpload.isRemoteFolderToBeCreated()) {
 +                    RemoteOperation operation = new CreateFolderOperation(  InstantUploadBroadcastReceiver.INSTANT_UPLOAD_DIR, 
 +                                                                            mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR).getFileId(), // TODO generalize this : INSTANT_UPLOAD_DIR could not be a child of root
 +                                                                            mStorageManager);
 +                    operation.execute(mUploadClient);      // ignoring result; fail could just mean that it already exists, but local database is not synchronized; the upload will be tried anyway
 +                }
  
              
 -            /// perform the upload
 -            RemoteOperationResult uploadResult = null;
 -            try {
 +                /// perform the upload
                  uploadResult = mCurrentUpload.execute(mUploadClient);
                  if (uploadResult.isSuccess()) {
                      saveUploadedFile();
                  }
                  
 +            } catch (AccountsException e) {
 +                Log.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
 +                uploadResult = new RemoteOperationResult(e);
 +                
 +            } catch (IOException e) {
 +                Log.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
 +                uploadResult = new RemoteOperationResult(e);
 +                
              } finally {
                  synchronized(mPendingUploads) {
                      mPendingUploads.remove(uploadKey);
                  }
              }
 -        
 +            
              /// notify result
              notifyUploadResult(uploadResult, mCurrentUpload);
              
@@@ -1,9 -1,9 +1,9 @@@
  /* ownCloud Android client application
-  *   Copyright (C) 2011  Bartek Przybylski
+  *   Copyright (C) 2012-2013 ownCloud Inc.
   *
   *   This program is free software: you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
-  *   the Free Software Foundation, either version 3 of the License, or
+  *   the Free Software Foundation, either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
@@@ -38,24 -38,18 +38,24 @@@ import org.apache.http.conn.ssl.Browser
  import org.apache.http.conn.ssl.X509HostnameVerifier;
  
  import com.owncloud.android.AccountUtils;
 +import com.owncloud.android.authenticator.AccountAuthenticator;
  
  import eu.alefzero.webdav.WebdavClient;
  
  import android.accounts.Account;
  import android.accounts.AccountManager;
 +import android.accounts.AccountManagerFuture;
 +import android.accounts.AuthenticatorException;
 +import android.accounts.OperationCanceledException;
 +import android.app.Activity;
  import android.content.Context;
  import android.net.Uri;
 +import android.os.Bundle;
  import android.util.Log;
  
  public class OwnCloudClientUtils {
      
 -    final private static String TAG = "OwnCloudClientFactory";
 +    final private static String TAG = OwnCloudClientUtils.class.getSimpleName();
      
      /** Default timeout for waiting data from the server */
      public static final int DEFAULT_DATA_TIMEOUT = 60000;
      /**
       * Creates a WebdavClient setup for an ownCloud account
       * 
 -     * @param account   The ownCloud account
 -     * @param context   The application context
 -     * @return          A WebdavClient object ready to be used
 +     * Do not call this method from the main thread.
 +     * 
 +     * @param account                       The ownCloud account
 +     * @param appContext                    Android application context
 +     * @return                              A WebdavClient object ready to be used
 +     * @throws AuthenticatorException       If the authenticator failed to get the authorization token for the account.
 +     * @throws OperationCanceledException   If the authenticator operation was cancelled while getting the authorization token for the account. 
 +     * @throws IOException                  If there was some I/O error while getting the authorization token for the account.
       */
 -    public static WebdavClient createOwnCloudClient (Account account, Context context) {
 -        Log.d(TAG, "Creating WebdavClient associated to " + account.name);
 +    public static WebdavClient createOwnCloudClient (Account account, Context appContext) throws OperationCanceledException, AuthenticatorException, IOException {
 +        //Log.d(TAG, "Creating WebdavClient associated to " + account.name);
         
 -        Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(context, account));
 -        WebdavClient client = createOwnCloudClient(uri, context);
 -        
 -        String username = account.name.substring(0, account.name.lastIndexOf('@'));
 -        String password = AccountManager.get(context).getPassword(account);
 -        //String password = am.blockingGetAuthToken(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE, true);
 +        Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account));
 +        WebdavClient client = createOwnCloudClient(uri, appContext);
 +        AccountManager am = AccountManager.get(appContext);
 +        if (am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null) {    // TODO avoid a call to getUserData here
 +            String accessToken = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, false);
 +            client.setBearerCredentials(accessToken);   // TODO not assume that the access token is a bearer token
          
 -        client.setCredentials(username, password);
 +        } else {
 +            String username = account.name.substring(0, account.name.lastIndexOf('@'));
 +            //String password = am.getPassword(account);
 +            String password = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD, false);
 +            client.setBasicCredentials(username, password);
 +        }
          
          return client;
      }
      
      
 -    /**
 -     * Creates a WebdavClient to try a new account before saving it
 -     * 
 -     * @param uri       URL to the ownCloud server
 -     * @param username  User name
 -     * @param password  User password
 -     * @param context   Android context where the WebdavClient is being created.
 -     * @return          A WebdavClient object ready to be used
 -     */
 -    public static WebdavClient createOwnCloudClient(Uri uri, String username, String password, Context context) {
 -        Log.d(TAG, "Creating WebdavClient for " + username + "@" + uri);
 -        
 -        WebdavClient client = createOwnCloudClient(uri, context);
 -        
 -        client.setCredentials(username, password);
 +    public static WebdavClient createOwnCloudClient (Account account, Context appContext, Activity currentActivity) throws OperationCanceledException, AuthenticatorException, IOException {
 +        Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account));
 +        WebdavClient client = createOwnCloudClient(uri, appContext);
 +        AccountManager am = AccountManager.get(appContext);
 +        if (am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null) {    // TODO avoid a call to getUserData here
 +            AccountManagerFuture<Bundle> future =  am.getAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, null, currentActivity, null, null);
 +            Bundle result = future.getResult();
 +            String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN);
 +            //String accessToken = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, false);
 +            if (accessToken == null) throw new AuthenticatorException("WTF!");
 +            client.setBearerCredentials(accessToken);   // TODO not assume that the access token is a bearer token
 +            
 +        } else {
 +            String username = account.name.substring(0, account.name.lastIndexOf('@'));
 +            //String password = am.getPassword(account);
 +            //String password = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD, false);
 +            AccountManagerFuture<Bundle> future =  am.getAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD, null, currentActivity, null, null);
 +            Bundle result = future.getResult();
 +            String password = result.getString(AccountManager.KEY_AUTHTOKEN);
 +            client.setBasicCredentials(username, password);
 +        }
          
          return client;
      }
 -    
 +
      
      /**
       * Creates a WebdavClient to access a URL and sets the desired parameters for ownCloud client connections.
       * @return          A WebdavClient object ready to be used
       */
      public static WebdavClient createOwnCloudClient(Uri uri, Context context) {
 -        Log.d(TAG, "Creating WebdavClient for " + uri);
 +        //Log.d(TAG, "Creating WebdavClient for " + uri);
          
          //allowSelfsignedCertificates(true);
          try {
      
      
      /**
-      * Allows or disallows self-signed certificates in ownCloud servers to reach
-      * 
-      * @param allow     'True' to allow, 'false' to disallow
-      */
-     public static void allowSelfsignedCertificates(boolean allow) {
-         Protocol pr = null;
-         try {
-             pr = Protocol.getProtocol("https");
-             if (pr != null && mDefaultHttpsProtocol == null) {
-               mDefaultHttpsProtocol = pr;
-             }
-         } catch (IllegalStateException e) {
-             // nothing to do here; really
-         }
-         boolean isAllowed = (pr != null && pr.getSocketFactory() instanceof EasySSLSocketFactory);
-         if (allow && !isAllowed) {
-             Protocol.registerProtocol("https", new Protocol("https", new EasySSLSocketFactory(), 443));
-         } else if (!allow && isAllowed) {
-               if (mDefaultHttpsProtocol != null) {
-                       Protocol.registerProtocol("https", mDefaultHttpsProtocol);
-               }
-         }
-     }
-     
-     /**
       * Registers or unregisters the proper components for advanced SSL handling.
       * @throws IOException 
       */
          return mConnManager;
      }
  
 +
  }
index e803616,0000000..7132c53
mode 100644,000000..100644
--- /dev/null
@@@ -1,138 -1,0 +1,138 @@@
-  *   Copyright (C) 2012 Bartek Przybylski
 +/* ownCloud Android client application
-  *   the Free Software Foundation, either version 3 of the License, or
++ *   Copyright (C) 2012-2013 ownCloud Inc.
 + *
 + *   This program is free software: you can redistribute it and/or modify
 + *   it under the terms of the GNU General Public License as published by
++ *   the Free Software Foundation, either version 2 of the License, or
 + *   (at your option) any later version.
 + *
 + *   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/>.
 + *
 + */
 +
 +package com.owncloud.android.operations;
 +
 +import org.apache.commons.httpclient.HttpStatus;
 +import org.apache.commons.httpclient.methods.GetMethod;
 +import org.json.JSONException;
 +import org.json.JSONObject;
 +
 +import com.owncloud.android.AccountUtils;
 +import com.owncloud.android.utils.OwnCloudVersion;
 +
 +import eu.alefzero.webdav.WebdavClient;
 +import android.content.Context;
 +import android.net.ConnectivityManager;
 +import android.net.Uri;
 +import android.util.Log;
 +
 +public class OwnCloudServerCheckOperation extends RemoteOperation {
 +    
 +    /** Maximum time to wait for a response from the server when the connection is being tested, in MILLISECONDs.  */
 +    public static final int TRY_CONNECTION_TIMEOUT = 5000;
 +    
 +    private static final String TAG = OwnCloudServerCheckOperation.class.getSimpleName();
 +    
 +    private String mUrl;
 +    private RemoteOperationResult mLatestResult;
 +    private Context mContext;
 +    private OwnCloudVersion mOCVersion;
 +
 +    public OwnCloudServerCheckOperation(String url, Context context) {
 +        mUrl = url;
 +        mContext = context;
 +        mOCVersion = null;
 +    }
 +    
 +    public OwnCloudVersion getDiscoveredVersion() {
 +        return mOCVersion;
 +    }
 +
 +    private boolean tryConnection(WebdavClient wc, String urlSt) {
 +        boolean retval = false;
 +        GetMethod get = null;
 +        try {
 +            get = new GetMethod(urlSt);
 +            int status = wc.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT);
 +            String response = get.getResponseBodyAsString();
 +            if (status == HttpStatus.SC_OK) {
 +                JSONObject json = new JSONObject(response);
 +                if (!json.getBoolean("installed")) {
 +                    mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
 +                } else {
 +                    mOCVersion = new OwnCloudVersion(json.getString("version"));
 +                    if (!mOCVersion.isVersionValid()) {
 +                        mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.BAD_OC_VERSION);
 +                        
 +                    } else {
 +                        mLatestResult = new RemoteOperationResult(urlSt.startsWith("https://") ? 
 +                                                                    RemoteOperationResult.ResultCode.OK_SSL : 
 +                                                                    RemoteOperationResult.ResultCode.OK_NO_SSL
 +                            );
 +
 +                        retval = true;
 +                    }
 +                }
 +                
 +            } else {
 +                mLatestResult = new RemoteOperationResult(false, status);
 +            }
 +
 +        } catch (JSONException e) {
 +            mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
 +            
 +        } catch (Exception e) {
 +            mLatestResult = new RemoteOperationResult(e);
 +            
 +        } finally {
 +            if (get != null)
 +                get.releaseConnection();
 +        }
 +        
 +        if (mLatestResult.isSuccess()) {
 +            Log.i(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage());
 +            
 +        } else if (mLatestResult.getException() != null) {
 +            Log.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage(), mLatestResult.getException());
 +            
 +        } else {
 +            Log.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage());
 +        }
 +
 +        return retval;
 +    }
 +
 +    private boolean isOnline() {
 +        ConnectivityManager cm = (ConnectivityManager) mContext
 +                .getSystemService(Context.CONNECTIVITY_SERVICE);
 +        return cm != null && cm.getActiveNetworkInfo() != null
 +                && cm.getActiveNetworkInfo().isConnectedOrConnecting();
 +    }
 +
 +      @Override
 +      protected RemoteOperationResult run(WebdavClient client) {
 +        if (!isOnline()) {
 +              return new RemoteOperationResult(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION);
 +        }
 +        if (mUrl.startsWith("http://") || mUrl.startsWith("https://")) {
 +            tryConnection(client, mUrl + AccountUtils.STATUS_PATH);
 +            
 +        } else {
 +            client.setBaseUri(Uri.parse("https://" + mUrl + AccountUtils.STATUS_PATH));
 +            boolean httpsSuccess = tryConnection(client, "https://" + mUrl + AccountUtils.STATUS_PATH); 
 +            if (!httpsSuccess && !mLatestResult.isSslRecoverableException()) {
 +                Log.d(TAG, "establishing secure connection failed, trying non secure connection");
 +                client.setBaseUri(Uri.parse("http://" + mUrl + AccountUtils.STATUS_PATH));
 +                tryConnection(client, "http://" + mUrl + AccountUtils.STATUS_PATH);
 +            }
 +        }
 +        return mLatestResult;
 +      }
 +      
 +}
@@@ -1,9 -1,9 +1,9 @@@
  /* ownCloud Android client application
-  *   Copyright (C) 2011  Bartek Przybylski
+  *   Copyright (C) 2012-2013 ownCloud Inc.
   *
   *   This program is free software: you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
-  *   the Free Software Foundation, either version 3 of the License, or
+  *   the Free Software Foundation, either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
   */
  package com.owncloud.android.operations;
  
 +import java.io.IOException;
 +
 +import org.apache.commons.httpclient.Credentials;
 +
 +import com.owncloud.android.authenticator.AccountAuthenticator;
 +import com.owncloud.android.network.BearerCredentials;
 +import com.owncloud.android.network.OwnCloudClientUtils;
 +import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
 +
 +import android.accounts.Account;
 +import android.accounts.AccountManager;
 +import android.accounts.AccountsException;
 +import android.app.Activity;
 +import android.content.Context;
  import android.os.Handler;
 +import android.util.Log;
  
  import eu.alefzero.webdav.WebdavClient;
  
   */
  public abstract class RemoteOperation implements Runnable {
        
 -      /** Object to interact with the ownCloud server */
 +    private static final String TAG = RemoteOperation.class.getSimpleName();
 +
 +    /** ownCloud account in the remote ownCloud server to operate */
 +    private Account mAccount = null;
 +    
 +    /** Android Application context */
 +    private Context mContext = null;
 +    
 +      /** Object to interact with the remote server */
        private WebdavClient mClient = null;
        
        /** Callback object to notify about the execution of the remote operation */
        /** Handler to the thread where mListener methods will be called */
        private Handler mListenerHandler = null;
  
 +      /** Activity */
 +    private Activity mCallerActivity;
 +
        
        /**
         *  Abstract method to implement the operation in derived classes.
         */
        protected abstract RemoteOperationResult run(WebdavClient client); 
        
 +
 +    /**
 +     * Synchronously executes the remote operation on the received ownCloud account.
 +     * 
 +     * Do not call this method from the main thread.
 +     * 
 +     * This method should be used whenever an ownCloud account is available, instead of {@link #execute(WebdavClient)}. 
 +     * 
 +     * @param account   ownCloud account in remote ownCloud server to reach during the execution of the operation.
 +     * @param context   Android context for the component calling the method.
 +     * @return          Result of the operation.
 +     */
 +    public final RemoteOperationResult execute(Account account, Context context) {
 +        if (account == null)
 +            throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account");
 +        if (context == null)
 +            throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context");
 +        mAccount = account;
 +        mContext = context.getApplicationContext();
 +        try {
 +            mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext);
 +        } catch (Exception e) {
 +            Log.e(TAG, "Error while trying to access to " + mAccount.name, e);
 +            return new RemoteOperationResult(e);
 +        }
 +        return run(mClient);
 +    }
 +    
        
        /**
         * Synchronously executes the remote operation
         * 
 +     * Do not call this method from the main thread.
 +     * 
         * @param client        Client object to reach an ownCloud server during the execution of the operation.
         * @return                      Result of the operation.
         */
        }
  
        
 +    /**
 +     * Asynchronously executes the remote operation
 +     * 
 +     * This method should be used whenever an ownCloud account is available, instead of {@link #execute(WebdavClient)}. 
 +     * 
 +     * @param account           ownCloud account in remote ownCloud server to reach during the execution of the operation.
 +     * @param context           Android context for the component calling the method.
 +     * @param listener          Listener to be notified about the execution of the operation.
 +     * @param listenerHandler   Handler associated to the thread where the methods of the listener objects must be called.
 +     * @return                  Thread were the remote operation is executed.
 +     */
 +    public final Thread execute(Account account, Context context, OnRemoteOperationListener listener, Handler listenerHandler, Activity callerActivity) {
 +        if (account == null)
 +            throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account");
 +        if (context == null)
 +            throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context");
 +        mAccount = account;
 +        mContext = context.getApplicationContext();
 +        mCallerActivity = callerActivity;
 +        mClient = null;     // the client instance will be created from mAccount and mContext in the runnerThread to create below
 +        
 +        if (listener == null) {
 +            throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a listener to notiy the result");
 +        }
 +        mListener = listener;
 +        
 +        if (listenerHandler == null) {
 +            throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a handler to the listener's thread");
 +        }
 +        mListenerHandler = listenerHandler;
 +        
 +        Thread runnerThread = new Thread(this);
 +        runnerThread.start();
 +        return runnerThread;
 +    }
 +
 +    
        /**
         * Asynchronously executes the remote operation
         * 
         * Asynchronous execution of the operation 
         * started by {@link RemoteOperation#execute(WebdavClient, OnRemoteOperationListener, Handler)}, 
         * and result posting.
 +       * 
 +       * TODO refactor && clean the code; now it's a mess
         */
      @Override
      public final void run() {
 -      final RemoteOperationResult result = execute(mClient);
 +        RemoteOperationResult result = null;
 +        boolean repeat = false;
 +        do {
 +            try{
 +                if (mClient == null) {
 +                    if (mAccount != null && mContext != null) {
 +                        if (mCallerActivity != null) {
 +                            mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext, mCallerActivity);
 +                        } else {
 +                            mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext);
 +                        }
 +                    } else {
 +                        throw new IllegalStateException("Trying to run a remote operation asynchronously with no client instance or account");
 +                    }
 +                }
 +            
 +            } catch (IOException e) {
 +                Log.e(TAG, "Error while trying to access to " + mAccount.name, new AccountsException("I/O exception while trying to authorize the account", e));
 +                result = new RemoteOperationResult(e);
 +            
 +            } catch (AccountsException e) {
 +                Log.e(TAG, "Error while trying to access to " + mAccount.name, e);
 +                result = new RemoteOperationResult(e);
 +            }
        
 +            if (result == null)
 +                result = run(mClient);
 +        
 +            repeat = false;
 +            if (mCallerActivity != null && mAccount != null && mContext != null && !result.isSuccess() && result.getCode() == ResultCode.UNAUTHORIZED) {
 +                /// fail due to lack of authorization in an operation performed in foreground
 +                AccountManager am = AccountManager.get(mContext);
 +                Credentials cred = mClient.getCredentials();
 +                if (cred instanceof BearerCredentials) {
 +                    am.invalidateAuthToken(AccountAuthenticator.ACCOUNT_TYPE, ((BearerCredentials)cred).getAccessToken());
 +                } else {
 +                    am.clearPassword(mAccount);
 +                }
 +                mClient = null;
 +                repeat = true;  // when repeated, the creation of a new OwnCloudClient after erasing the saved credentials will trigger the login activity
 +                result = null;
 +            }
 +        } while (repeat);
 +        
 +        final RemoteOperationResult resultToSend = result;
          if (mListenerHandler != null && mListener != null) {
                mListenerHandler.post(new Runnable() {
                  @Override
                  public void run() {
 -                    mListener.onRemoteOperationFinish(RemoteOperation.this, result);
 +                    mListener.onRemoteOperationFinish(RemoteOperation.this, resultToSend);
                  }
              });
          }
      }
 -      
 -      
 +
 +
 +    /**
 +     * Returns the current client instance to access the remote server.
 +     * 
 +     * @return      Current client instance to access the remote server.
 +     */
 +    public final WebdavClient getClient() {
 +        return mClient;
 +    }
 +
  }
@@@ -1,9 -1,10 +1,10 @@@
  /* ownCloud Android client application
   *   Copyright (C) 2012 Bartek Przybylski
+  *   Copyright (C) 2012-2013 ownCloud Inc.
   *
   *   This program is free software: you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
-  *   the Free Software Foundation, either version 3 of the License, or
+  *   the Free Software Foundation, either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
@@@ -46,6 -47,7 +47,6 @@@ public class RemoteOperationResult impl
      
      /** Generated - should be refreshed every time the class changes!! */
      private static final long serialVersionUID = -7805531062432602444L;
 -
      
      public enum ResultCode { 
          OK,
          INVALID_LOCAL_FILE_NAME, 
          INVALID_OVERWRITE,
          CONFLICT, 
 +        OAUTH2_ERROR,
          SYNC_CONFLICT,
          LOCAL_STORAGE_FULL, 
          LOCAL_STORAGE_NOT_MOVED, 
 -        LOCAL_STORAGE_NOT_COPIED
 +        LOCAL_STORAGE_NOT_COPIED, 
 +        OAUTH2_ERROR_ACCESS_DENIED
      }
  
      private boolean mSuccess = false;
@@@ -1,9 -1,9 +1,9 @@@
  /* ownCloud Android client application
-  *   Copyright (C) 2012 Bartek Przybylski
+  *   Copyright (C) 2012-2013 ownCloud Inc.
   *
   *   This program is free software: you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
-  *   the Free Software Foundation, either version 3 of the License, or
+  *   the Free Software Foundation, either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
@@@ -42,7 -42,7 +42,7 @@@ import eu.alefzero.webdav.WebdavUtils
   */
  public class RenameFileOperation extends RemoteOperation {
      
 -    private static final String TAG = RemoveFileOperation.class.getSimpleName();
 +    private static final String TAG = RenameFileOperation.class.getSimpleName();
  
      private static final int RENAME_READ_TIMEOUT = 10000;
      private static final int RENAME_CONNECTION_TIMEOUT = 5000;
@@@ -1,9 -1,10 +1,10 @@@
  /* ownCloud Android client application\r
   *   Copyright (C) 2011  Bartek Przybylski\r
+  *   Copyright (C) 2012-2013 ownCloud Inc.\r
   *\r
   *   This program is free software: you can redistribute it and/or modify\r
   *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 3 of the License, or\r
+  *   the Free Software Foundation, either version 2 of the License, or\r
   *   (at your option) any later version.\r
   *\r
   *   This program is distributed in the hope that it will be useful,\r
@@@ -142,7 -143,7 +143,7 @@@ public abstract class AbstractOwnCloudS
          return null;\r
      }\r
  \r
 -    protected void initClientForCurrentAccount() throws UnknownHostException {\r
 +    protected void initClientForCurrentAccount() throws OperationCanceledException, AuthenticatorException, IOException {\r
          if (AccountUtils.constructFullURLForAccount(getContext(), account) == null) {\r
              throw new UnknownHostException();\r
          }\r
@@@ -1,9 -1,10 +1,10 @@@
  /* ownCloud Android client application\r
   *   Copyright (C) 2011  Bartek Przybylski\r
+  *   Copyright (C) 2012-2013 ownCloud Inc.\r
   *\r
   *   This program is free software: you can redistribute it and/or modify\r
   *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 3 of the License, or\r
+  *   the Free Software Foundation, either version 2 of the License, or\r
   *   (at your option) any later version.\r
   *\r
   *   This program is distributed in the hope that it will be useful,\r
@@@ -19,6 -20,7 +20,6 @@@
  package com.owncloud.android.syncadapter;\r
  \r
  import java.io.IOException;\r
 -import java.net.UnknownHostException;\r
  import java.util.ArrayList;\r
  import java.util.HashMap;\r
  import java.util.List;\r
@@@ -34,11 -36,8 +35,11 @@@ import com.owncloud.android.operations.
  import com.owncloud.android.operations.SynchronizeFolderOperation;\r
  import com.owncloud.android.operations.UpdateOCVersionOperation;\r
  import com.owncloud.android.operations.RemoteOperationResult.ResultCode;\r
 +import com.owncloud.android.ui.activity.AuthenticatorActivity;\r
  import com.owncloud.android.ui.activity.ErrorsWhileCopyingHandlerActivity;\r
 +\r
  import android.accounts.Account;\r
 +import android.accounts.AccountsException;\r
  import android.app.Notification;\r
  import android.app.NotificationManager;\r
  import android.app.PendingIntent;\r
@@@ -104,12 -103,7 +105,12 @@@ public class FileSyncAdapter extends Ab
          this.setStorageManager(new FileDataStorageManager(account, getContentProvider()));\r
          try {\r
              this.initClientForCurrentAccount();\r
 -        } catch (UnknownHostException e) {\r
 +        } catch (IOException e) {\r
 +            /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again\r
 +            mSyncResult.tooManyRetries = true;\r
 +            notifyFailedSynchronization();\r
 +            return;\r
 +        } catch (AccountsException e) {\r
              /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again\r
              mSyncResult.tooManyRetries = true;\r
              notifyFailedSynchronization();\r
              RemoteOperationResult.ResultCode code = failedResult.getCode();\r
              return (code.equals(RemoteOperationResult.ResultCode.SSL_ERROR) ||\r
                      code.equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) ||\r
 +                    code.equals(RemoteOperationResult.ResultCode.UNAUTHORIZED) ||\r
                      code.equals(RemoteOperationResult.ResultCode.BAD_OC_VERSION) ||\r
                      code.equals(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED));\r
          }\r
      private void notifyFailedSynchronization() {\r
          Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_ticker), System.currentTimeMillis());\r
          notification.flags |= Notification.FLAG_AUTO_CANCEL;\r
 -        // TODO put something smart in the contentIntent below\r
 +        boolean needsToUpdateCredentials = (mLastFailedResult != null && mLastFailedResult.getCode() == ResultCode.UNAUTHORIZED);\r
 +        // TODO put something smart in the contentIntent below for all the possible errors\r
          notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);\r
 -        notification.setLatestEventInfo(getContext().getApplicationContext(), \r
 -                                        getContext().getString(R.string.sync_fail_ticker), \r
 -                                        String.format(getContext().getString(R.string.sync_fail_content), getAccount().name), \r
 -                                        notification.contentIntent);\r
 +        if (needsToUpdateCredentials) {\r
 +            // let the user update credentials with one click\r
 +            Intent updateAccountCredentials = new Intent(getContext(), AuthenticatorActivity.class);\r
 +            updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, getAccount());\r
 +            updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);\r
 +            updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\r
 +            updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);\r
 +            updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);\r
 +            notification.contentIntent = PendingIntent.getActivity(getContext(), (int)System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT);\r
 +            notification.setLatestEventInfo(getContext().getApplicationContext(), \r
 +                    getContext().getString(R.string.sync_fail_ticker), \r
 +                    String.format(getContext().getString(R.string.sync_fail_content_unauthorized), getAccount().name), \r
 +                    notification.contentIntent);\r
 +            Log.e(TAG, "NEEDS TO UPDATE CREDENTIALS");\r
 +        } else {\r
 +            notification.setLatestEventInfo(getContext().getApplicationContext(), \r
 +                    getContext().getString(R.string.sync_fail_ticker), \r
 +                    String.format(getContext().getString(R.string.sync_fail_content), getAccount().name), \r
 +                    notification.contentIntent);\r
 +        }\r
          ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_ticker, notification);\r
      }\r
  \r
@@@ -1,9 -1,10 +1,10 @@@
  /* ownCloud Android client application
   *   Copyright (C) 2012 Bartek Przybylski
+  *   Copyright (C) 2012-2013 ownCloud Inc.
   *
   *   This program is free software: you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
-  *   the Free Software Foundation, either version 3 of the License, or
+  *   the Free Software Foundation, either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
@@@ -94,10 -95,10 +95,10 @@@ public class AccountSelectActivity exte
                  /// the account set as default changed since this activity was created 
              
                  // trigger synchronization
 -                ContentResolver.cancelSync(null, AccountAuthenticator.AUTH_TOKEN_TYPE);
 +                ContentResolver.cancelSync(null, AccountAuthenticator.AUTHORITY);
                  Bundle bundle = new Bundle();
                  bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
 -                ContentResolver.requestSync(AccountUtils.getCurrentOwnCloudAccount(this), AccountAuthenticator.AUTH_TOKEN_TYPE, bundle);
 +                ContentResolver.requestSync(AccountUtils.getCurrentOwnCloudAccount(this), AccountAuthenticator.AUTHORITY, bundle);
                  
                  // restart the main activity
                  Intent i = new Intent(this, FileDisplayActivity.class);
              Intent intent = new Intent(
                      android.provider.Settings.ACTION_ADD_ACCOUNT);
              intent.putExtra("authorities",
 -                    new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });
 +                    new String[] { AccountAuthenticator.AUTHORITY });
              startActivity(intent);
              return true;
          }
@@@ -1,10 -1,10 +1,10 @@@
  /* ownCloud Android client application\r
   *   Copyright (C) 2012  Bartek Przybylski\r
-  *   Copyright (C) 2012-2013  ownCloud Inc.\r
+  *   Copyright (C) 2012-2013 ownCloud Inc.\r
   *\r
   *   This program is free software: you can redistribute it and/or modify\r
   *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 3 of the License, or\r
+  *   the Free Software Foundation, either version 2 of the License, or\r
   *   (at your option) any later version.\r
   *\r
   *   This program is distributed in the hope that it will be useful,\r
  \r
  package com.owncloud.android.ui.activity;\r
  \r
 -import java.net.MalformedURLException;\r
 -import java.net.URL;\r
 -\r
  import com.owncloud.android.AccountUtils;\r
  import com.owncloud.android.authenticator.AccountAuthenticator;\r
 -import com.owncloud.android.authenticator.AuthenticationRunnable;\r
 -import com.owncloud.android.authenticator.OnAuthenticationResultListener;\r
 -import com.owncloud.android.authenticator.OnConnectCheckListener;\r
 +import com.owncloud.android.authenticator.oauth2.OAuth2Context;\r
  import com.owncloud.android.ui.dialog.SslValidatorDialog;\r
  import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;\r
 +import com.owncloud.android.utils.OwnCloudVersion;\r
  import com.owncloud.android.network.OwnCloudClientUtils;\r
 -import com.owncloud.android.operations.ConnectionCheckOperation;\r
 +import com.owncloud.android.operations.OwnCloudServerCheckOperation;\r
 +import com.owncloud.android.operations.ExistenceCheckOperation;\r
 +import com.owncloud.android.operations.OAuth2GetAccessToken;\r
  import com.owncloud.android.operations.OnRemoteOperationListener;\r
  import com.owncloud.android.operations.RemoteOperation;\r
  import com.owncloud.android.operations.RemoteOperationResult;\r
 +import com.owncloud.android.operations.RemoteOperationResult.ResultCode;\r
  \r
  import android.accounts.Account;\r
  import android.accounts.AccountAuthenticatorActivity;\r
@@@ -51,15 -52,13 +51,15 @@@ import android.preference.PreferenceMan
  import android.text.InputType;\r
  import android.util.Log;\r
  import android.view.View;\r
 -import android.view.View.OnClickListener;\r
  import android.view.View.OnFocusChangeListener;\r
  import android.view.Window;\r
 -import android.widget.Button;\r
 +import android.widget.CheckBox;\r
  import android.widget.EditText;\r
 +import android.widget.Button;\r
  import android.widget.ImageView;\r
  import android.widget.TextView;\r
 +import android.widget.Toast;\r
 +\r
  import com.owncloud.android.R;\r
  \r
  import eu.alefzero.webdav.WebdavClient;\r
   * This Activity is used to add an ownCloud account to the App\r
   * \r
   * @author Bartek Przybylski\r
 - * \r
 + * @author David A. Velasco\r
   */\r
  public class AuthenticatorActivity extends AccountAuthenticatorActivity\r
 -        implements OnAuthenticationResultListener, OnConnectCheckListener, OnRemoteOperationListener, OnSslValidatorListener, \r
 -        OnFocusChangeListener, OnClickListener {\r
 +        implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeListener {\r
 +\r
 +    private static final String TAG = AuthenticatorActivity.class.getSimpleName();\r
 +\r
 +    public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
 +    public static final String EXTRA_USER_NAME = "USER_NAME";\r
 +    public static final String EXTRA_HOST_NAME = "HOST_NAME";\r
 +    public static final String EXTRA_ACTION = "ACTION";\r
 +    \r
 +    private static final String KEY_HOST_URL_TEXT = "HOST_URL_TEXT";\r
 +    private static final String KEY_OC_VERSION = "OC_VERSION";\r
 +    private static final String KEY_ACCOUNT = "ACCOUNT";\r
 +    private static final String KEY_STATUS_TEXT = "STATUS_TEXT";\r
 +    private static final String KEY_STATUS_ICON = "STATUS_ICON";\r
 +    private static final String KEY_STATUS_CORRECT = "STATUS_CORRECT";\r
 +    private static final String KEY_IS_SSL_CONN = "IS_SSL_CONN";\r
 +    private static final String KEY_OAUTH2_STATUS_TEXT = "OAUTH2_STATUS_TEXT";\r
 +    private static final String KEY_OAUTH2_STATUS_ICON = "OAUTH2_STATUS_ICON";\r
  \r
      private static final int DIALOG_LOGIN_PROGRESS = 0;\r
      private static final int DIALOG_SSL_VALIDATOR = 1;\r
      private static final int DIALOG_CERT_NOT_SAVED = 2;\r
 +    private static final int DIALOG_OAUTH2_LOGIN_PROGRESS = 3;\r
  \r
 -    private static final String TAG = "AuthActivity";\r
 +    public static final byte ACTION_CREATE = 0;\r
 +    public static final byte ACTION_UPDATE_TOKEN = 1;\r
  \r
 -    private Thread mAuthThread;\r
 -    private AuthenticationRunnable mAuthRunnable;\r
 -    //private ConnectionCheckerRunnable mConnChkRunnable = null;\r
 -    private ConnectionCheckOperation mConnChkRunnable;\r
 -    private final Handler mHandler = new Handler();\r
 -    private String mBaseUrl;\r
      \r
 -    private static final String STATUS_TEXT = "STATUS_TEXT";\r
 -    private static final String STATUS_ICON = "STATUS_ICON";\r
 -    private static final String STATUS_CORRECT = "STATUS_CORRECT";\r
 -    private static final String IS_SSL_CONN = "IS_SSL_CONN";\r
 +    private String mHostBaseUrl;\r
 +    private OwnCloudVersion mDiscoveredVersion;\r
 +    \r
      private int mStatusText, mStatusIcon;\r
      private boolean mStatusCorrect, mIsSslConn;\r
 +    private int mOAuth2StatusText, mOAuth2StatusIcon;    \r
 +    \r
 +    private final Handler mHandler = new Handler();\r
 +    private Thread mOperationThread;\r
 +    private OwnCloudServerCheckOperation mOcServerChkOperation;\r
 +    private ExistenceCheckOperation mAuthCheckOperation;\r
      private RemoteOperationResult mLastSslUntrustedServerResult;\r
  \r
 -    public static final String PARAM_USERNAME = "param_Username";\r
 -    public static final String PARAM_HOSTNAME = "param_Hostname";\r
 -\r
 +    //private Thread mOAuth2GetCodeThread;\r
 +    //private OAuth2GetAuthorizationToken mOAuth2GetCodeRunnable;     \r
 +    //private TokenReceiver tokenReceiver;\r
 +    //private JSONObject mCodeResponseJson; \r
 +    private Uri mNewCapturedUriFromOAuth2Redirection;\r
 +    \r
 +    private AccountManager mAccountMgr;\r
 +    private boolean mJustCreated;\r
 +    private byte mAction;\r
 +    private Account mAccount;\r
 +    \r
 +    private ImageView mRefreshButton;\r
 +    private ImageView mViewPasswordButton;\r
 +    private EditText mHostUrlInput;\r
 +    private EditText mUsernameInput;\r
 +    private EditText mPasswordInput;\r
 +    private CheckBox mOAuth2Check;\r
 +    private String mOAuthAccessToken;\r
 +    private View mOkButton;\r
 +    private TextView mAuthStatusLayout;\r
 +    \r
 +    private TextView mOAuthAuthEndpointText;\r
 +    private TextView mOAuthTokenEndpointText;\r
 +    \r
 +    \r
 +    /**\r
 +     * {@inheritDoc}\r
 +     * \r
 +     * IMPORTANT ENTRY POINT 1: activity is shown to the user\r
 +     */\r
      @Override\r
      protected void onCreate(Bundle savedInstanceState) {\r
          super.onCreate(savedInstanceState);\r
          getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
 +        \r
 +        /// set view and get references to view elements\r
          setContentView(R.layout.account_setup);\r
 -        ImageView iv = (ImageView) findViewById(R.id.refreshButton);\r
 -        ImageView iv2 = (ImageView) findViewById(R.id.viewPassword);\r
 -        TextView tv = (TextView) findViewById(R.id.host_URL);\r
 -        TextView tv2 = (TextView) findViewById(R.id.account_password);\r
 -\r
 -        if (savedInstanceState != null) {\r
 -            mStatusIcon = savedInstanceState.getInt(STATUS_ICON);\r
 -            mStatusText = savedInstanceState.getInt(STATUS_TEXT);\r
 -            mStatusCorrect = savedInstanceState.getBoolean(STATUS_CORRECT);\r
 -            mIsSslConn = savedInstanceState.getBoolean(IS_SSL_CONN);\r
 -            setResultIconAndText(mStatusIcon, mStatusText);\r
 -            findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);\r
 -            if (!mStatusCorrect)\r
 -                iv.setVisibility(View.VISIBLE);\r
 -            else\r
 -                iv.setVisibility(View.INVISIBLE);\r
 +        mRefreshButton = (ImageView) findViewById(R.id.refreshButton);\r
 +        mViewPasswordButton = (ImageView) findViewById(R.id.viewPasswordButton);\r
 +        mHostUrlInput = (EditText) findViewById(R.id.hostUrlInput);\r
 +        mUsernameInput = (EditText) findViewById(R.id.account_username);\r
 +        mPasswordInput = (EditText) findViewById(R.id.account_password);\r
 +        mOAuthAuthEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_1);\r
 +        mOAuthTokenEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_2);\r
 +        mOAuth2Check = (CheckBox) findViewById(R.id.oauth_onOff_check);\r
 +        mOkButton = findViewById(R.id.buttonOK);\r
 +        mAuthStatusLayout = (TextView) findViewById(R.id.auth_status_text); \r
 +        \r
  \r
 -        } else {\r
 +        /// complete label for 'register account' button\r
 +        Button b = (Button) findViewById(R.id.account_register);\r
 +        if (b != null) {\r
 +            b.setText(String.format(getString(R.string.auth_register), getString(R.string.app_name)));\r
 +        }\r
 +\r
 +        /// bind view elements to listeners\r
 +        mHostUrlInput.setOnFocusChangeListener(this);\r
 +        mPasswordInput.setOnFocusChangeListener(this);\r
 +        \r
 +        /// initialization\r
 +        mAccountMgr = AccountManager.get(this);\r
 +        mNewCapturedUriFromOAuth2Redirection = null;    // TODO save?\r
 +        mAction = getIntent().getByteExtra(EXTRA_ACTION, ACTION_CREATE); \r
 +        mAccount = null;\r
 +\r
 +        if (savedInstanceState == null) {\r
 +            /// connection state and info\r
              mStatusText = mStatusIcon = 0;\r
              mStatusCorrect = false;\r
              mIsSslConn = false;\r
 -        }\r
 -        iv.setOnClickListener(this);\r
 -        iv2.setOnClickListener(this);\r
 -        tv.setOnFocusChangeListener(this);\r
 -        tv2.setOnFocusChangeListener(this);\r
 +            \r
 +            /// retrieve extras from intent\r
 +            String tokenType = getIntent().getExtras().getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE);\r
 +            boolean oAuthRequired = AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN.equals(tokenType);\r
 +            \r
 +            mAccount = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT);\r
 +            if (mAccount != null) {\r
 +                String ocVersion = mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION);\r
 +                if (ocVersion != null) {\r
 +                    mDiscoveredVersion = new OwnCloudVersion(ocVersion);\r
 +                }\r
 +                mHostBaseUrl = mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL);\r
 +                mHostUrlInput.setText(mHostBaseUrl);\r
 +                String userName = mAccount.name.substring(0, mAccount.name.lastIndexOf('@'));\r
 +                mUsernameInput.setText(userName);\r
 +                oAuthRequired = (mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null);\r
 +            }\r
 +            mOAuth2Check.setChecked(oAuthRequired);\r
 +            changeViewByOAuth2Check(oAuthRequired);\r
 +            \r
  \r
 -        Button b = (Button) findViewById(R.id.account_register);\r
 -        if (b != null) {\r
 -            b.setText(String.format(getString(R.string.auth_register), getString(R.string.app_name)));\r
 +        } else {\r
 +            loadSavedInstanceState(savedInstanceState);\r
 +        }\r
 +        \r
 +        if (mAction == ACTION_UPDATE_TOKEN) {\r
 +            /// lock things that should not change\r
 +            mHostUrlInput.setEnabled(false);\r
 +            mUsernameInput.setEnabled(false);\r
 +            mOAuth2Check.setVisibility(View.GONE);\r
 +            checkOcServer(); \r
          }\r
 +        \r
 +        mPasswordInput.setText("");     // clean password to avoid social hacking (disadvantage: password in removed if the device is turned aside)\r
 +        mJustCreated = true;\r
      }\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
 +     * \r
 +     * See {@link #loadSavedInstanceState(Bundle)}\r
 +     */\r
      @Override\r
      protected void onSaveInstanceState(Bundle outState) {\r
 -        outState.putInt(STATUS_ICON, mStatusIcon);\r
 -        outState.putInt(STATUS_TEXT, mStatusText);\r
 -        outState.putBoolean(STATUS_CORRECT, mStatusCorrect);\r
          super.onSaveInstanceState(outState);\r
 +        \r
 +        /// connection state and info\r
 +        outState.putInt(KEY_STATUS_TEXT, mStatusText);\r
 +        outState.putInt(KEY_STATUS_ICON, mStatusIcon);\r
 +        outState.putBoolean(KEY_STATUS_CORRECT, mStatusCorrect);\r
 +        outState.putBoolean(KEY_IS_SSL_CONN, mIsSslConn);\r
 +\r
 +        /// server data\r
 +        if (mDiscoveredVersion != null) \r
 +            outState.putString(KEY_OC_VERSION, mDiscoveredVersion.toString());\r
 +        outState.putString(KEY_HOST_URL_TEXT, mHostBaseUrl);\r
 +        \r
 +        /// account data, if updating\r
 +        if (mAccount != null)\r
 +            outState.putParcelable(KEY_ACCOUNT, mAccount);\r
 +        \r
 +        // Saving the state of oAuth2 components.\r
 +        outState.putInt(KEY_OAUTH2_STATUS_ICON, mOAuth2StatusIcon);\r
 +        outState.putInt(KEY_OAUTH2_STATUS_TEXT, mOAuth2StatusText);\r
 +        \r
 +        /* Leave old OAuth flow\r
 +        if (codeResponseJson != null){\r
 +            outState.putString(KEY_OAUTH2_CODE_RESULT, codeResponseJson.toString());\r
 +        }\r
 +        */\r
      }\r
  \r
 +\r
 +    /**\r
 +     * Loads saved state\r
 +     * \r
 +     * See {@link #onSaveInstanceState(Bundle)}.\r
 +     * \r
 +     * @param savedInstanceState    Saved state, as received in {@link #onCreate(Bundle)}.\r
 +     */\r
 +    private void loadSavedInstanceState(Bundle savedInstanceState) {\r
 +        /// connection state and info\r
 +        mStatusCorrect = savedInstanceState.getBoolean(KEY_STATUS_CORRECT);\r
 +        mIsSslConn = savedInstanceState.getBoolean(KEY_IS_SSL_CONN);\r
 +        mStatusText = savedInstanceState.getInt(KEY_STATUS_TEXT);\r
 +        mStatusIcon = savedInstanceState.getInt(KEY_STATUS_ICON);\r
 +        updateConnStatus();\r
 +        \r
 +        /// UI settings depending upon connection\r
 +        mOkButton.setEnabled(mStatusCorrect);   // TODO really necessary?\r
 +        if (!mStatusCorrect)\r
 +            mRefreshButton.setVisibility(View.VISIBLE); // seems that setting visibility is necessary\r
 +        else\r
 +            mRefreshButton.setVisibility(View.INVISIBLE);\r
 +        \r
 +        /// server data\r
 +        String ocVersion = savedInstanceState.getString(KEY_OC_VERSION);\r
 +        if (ocVersion != null)\r
 +            mDiscoveredVersion = new OwnCloudVersion(ocVersion);\r
 +        mHostBaseUrl = savedInstanceState.getString(KEY_HOST_URL_TEXT);\r
 +        \r
 +        // account data, if updating\r
 +        mAccount = savedInstanceState.getParcelable(KEY_ACCOUNT);\r
 +        \r
 +        // state of oAuth2 components\r
 +        mOAuth2StatusIcon = savedInstanceState.getInt(KEY_OAUTH2_STATUS_ICON);\r
 +        mOAuth2StatusText = savedInstanceState.getInt(KEY_OAUTH2_STATUS_TEXT);\r
 +        \r
 +        /* Leave old OAuth flow\r
 +        // We store a JSon object with all the data returned from oAuth2 server when we get user_code.\r
 +        // Is better than store variable by variable. We use String object to serialize from/to it.\r
 +           try {\r
 +            if (savedInstanceState.containsKey(KEY_OAUTH2_CODE_RESULT)) {\r
 +                codeResponseJson = new JSONObject(savedInstanceState.getString(KEY_OAUTH2_CODE_RESULT));\r
 +            }\r
 +        } catch (JSONException e) {\r
 +            Log.e(TAG, "onCreate->JSONException: " + e.toString());\r
 +        }*/\r
 +        // END of getting the state of oAuth2 components.\r
 +        \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
 +     * \r
 +     * To make this possible, this activity needs to be qualified with android:launchMode = "singleTask" in the\r
 +     * AndroidManifest.xml file.\r
 +     */\r
      @Override\r
 -    protected Dialog onCreateDialog(int id) {\r
 -        Dialog dialog = null;\r
 -        switch (id) {\r
 -        case DIALOG_LOGIN_PROGRESS: {\r
 -            ProgressDialog working_dialog = new ProgressDialog(this);\r
 -            working_dialog.setMessage(getResources().getString(\r
 -                    R.string.auth_trying_to_login));\r
 -            working_dialog.setIndeterminate(true);\r
 -            working_dialog.setCancelable(true);\r
 -            working_dialog\r
 -                    .setOnCancelListener(new DialogInterface.OnCancelListener() {\r
 -                        @Override\r
 -                        public void onCancel(DialogInterface dialog) {\r
 -                            Log.i(TAG, "Login canceled");\r
 -                            if (mAuthThread != null) {\r
 -                                mAuthThread.interrupt();\r
 -                                finish();\r
 -                            }\r
 -                        }\r
 -                    });\r
 -            dialog = working_dialog;\r
 -            break;\r
 -        }\r
 -        case DIALOG_SSL_VALIDATOR: {\r
 -            dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);\r
 -            break;\r
 -        }\r
 -        case DIALOG_CERT_NOT_SAVED: {\r
 -            AlertDialog.Builder builder = new AlertDialog.Builder(this);\r
 -            builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));\r
 -            builder.setCancelable(false);\r
 -            builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {\r
 -                    @Override\r
 -                    public void onClick(DialogInterface dialog, int which) {\r
 -                        dialog.dismiss();\r
 -                    };\r
 -                });\r
 -            dialog = builder.create();\r
 -            break;\r
 +    protected void onNewIntent (Intent intent) {\r
 +        Log.d(TAG, "onNewIntent()");\r
 +        Uri data = intent.getData();\r
 +        if (data != null && data.toString().startsWith(OAuth2Context.MY_REDIRECT_URI)) {\r
 +            mNewCapturedUriFromOAuth2Redirection = data;\r
          }\r
 -        default:\r
 -            Log.e(TAG, "Incorrect dialog called with id = " + id);\r
 -        }\r
 -        return dialog;\r
      }\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
 +     */\r
      @Override\r
 -    protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {\r
 -        switch (id) {\r
 -        case DIALOG_LOGIN_PROGRESS:\r
 -        case DIALOG_CERT_NOT_SAVED:\r
 -            break;\r
 -        case DIALOG_SSL_VALIDATOR: {\r
 -            ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);\r
 -            break;\r
 +    protected void onResume() {\r
 +        super.onResume();\r
 +        // the state of mOAuth2Check is automatically recovered between configuration changes, but not before onCreate() finishes; so keep the next lines here\r
 +        changeViewByOAuth2Check(mOAuth2Check.isChecked());  \r
 +        if (mAction == ACTION_UPDATE_TOKEN && mJustCreated) {\r
 +            if (mOAuth2Check.isChecked())\r
 +                Toast.makeText(this, R.string.auth_expired_oauth_token_toast, Toast.LENGTH_LONG).show();\r
 +            else\r
 +                Toast.makeText(this, R.string.auth_expired_basic_auth_toast, Toast.LENGTH_LONG).show();\r
          }\r
 -        default:\r
 -            Log.e(TAG, "Incorrect dialog called with id = " + id);\r
 +           \r
 +        \r
 +        /* LEAVE OLD OAUTH FLOW ; \r
 +        // (old oauth code) Registering token receiver. We must listening to the service that is pooling to the oAuth server for a token.\r
 +        if (tokenReceiver == null) {\r
 +            IntentFilter tokenFilter = new IntentFilter(OAuth2GetTokenService.TOKEN_RECEIVED_MESSAGE);                \r
 +            tokenReceiver = new TokenReceiver();\r
 +            this.registerReceiver(tokenReceiver,tokenFilter);\r
 +        } */\r
 +        // (new oauth code)\r
 +        if (mNewCapturedUriFromOAuth2Redirection != null) {\r
 +            getOAuth2AccessTokenFromCapturedRedirection();            \r
          }\r
 +        \r
 +        mJustCreated = false;\r
      }\r
 +    \r
 +    \r
 +    @Override protected void onDestroy() {       \r
 +        super.onDestroy();\r
  \r
 -    public void onAuthenticationResult(boolean success, String message) {\r
 -        if (success) {\r
 -            TextView username_text = (TextView) findViewById(R.id.account_username), password_text = (TextView) findViewById(R.id.account_password);\r
 +        /* LEAVE OLD OAUTH FLOW\r
 +        // We must stop the service thats it's pooling to oAuth2 server for a token.\r
 +        Intent tokenService = new Intent(this, OAuth2GetTokenService.class);\r
 +        stopService(tokenService);\r
 +        \r
 +        // We stop listening the result of the pooling service.\r
 +        if (tokenReceiver != null) {\r
 +            unregisterReceiver(tokenReceiver);\r
 +            tokenReceiver = null;\r
 +        }*/\r
  \r
 -            URL url;\r
 -            try {\r
 -                url = new URL(message);\r
 -            } catch (MalformedURLException e) {\r
 -                // should never happen\r
 -                Log.e(getClass().getName(), "Malformed URL: " + message);\r
 -                return;\r
 -            }\r
 +    }    \r
 +    \r
 +    \r
 +    /**\r
 +     * Parses the redirection with the response to the GET AUTHORIZATION request to the \r
 +     * oAuth server and requests for the access token (GET ACCESS TOKEN)\r
 +     */\r
 +    private void getOAuth2AccessTokenFromCapturedRedirection() {\r
 +        /// Parse data from OAuth redirection\r
 +        String queryParameters = mNewCapturedUriFromOAuth2Redirection.getQuery();\r
 +        mNewCapturedUriFromOAuth2Redirection = null;\r
 +        \r
 +        /// Showing the dialog with instructions for the user.\r
 +        showDialog(DIALOG_OAUTH2_LOGIN_PROGRESS);\r
  \r
 -            String username = username_text.getText().toString().trim();\r
 -            String accountName = username + "@" + url.getHost();\r
 -            if (url.getPort() >= 0) {\r
 -                accountName += ":" + url.getPort();\r
 -            }\r
 -            Account account = new Account(accountName,\r
 -                    AccountAuthenticator.ACCOUNT_TYPE);\r
 -            AccountManager accManager = AccountManager.get(this);\r
 -            accManager.addAccountExplicitly(account, password_text.getText()\r
 -                    .toString(), null);\r
 -\r
 -            // Add this account as default in the preferences, if there is none\r
 -            // already\r
 -            Account defaultAccount = AccountUtils\r
 -                    .getCurrentOwnCloudAccount(this);\r
 -            if (defaultAccount == null) {\r
 -                SharedPreferences.Editor editor = PreferenceManager\r
 -                        .getDefaultSharedPreferences(this).edit();\r
 -                editor.putString("select_oc_account", accountName);\r
 -                editor.commit();\r
 -            }\r
 +        /// GET ACCESS TOKEN to the oAuth server \r
 +        RemoteOperation operation = new OAuth2GetAccessToken(queryParameters);\r
 +        WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(getString(R.string.oauth_url_endpoint_access)), getApplicationContext());\r
 +        operation.execute(client, this, mHandler);\r
 +    }\r
 +    \r
  \r
 -            final Intent intent = new Intent();\r
 -            intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE,\r
 -                    AccountAuthenticator.ACCOUNT_TYPE);\r
 -            intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);\r
 -            intent.putExtra(AccountManager.KEY_AUTHTOKEN,\r
 -                    AccountAuthenticator.ACCOUNT_TYPE);\r
 -            intent.putExtra(AccountManager.KEY_USERDATA, username);\r
 -\r
 -            accManager.setUserData(account,\r
 -                    AccountAuthenticator.KEY_OC_VERSION, mConnChkRunnable\r
 -                            .getDiscoveredVersion().toString());\r
 +    \r
 +    /**\r
 +     * Handles the change of focus on the text inputs for the server URL and the password\r
 +     */\r
 +    public void onFocusChange(View view, boolean hasFocus) {\r
 +        if (view.getId() == R.id.hostUrlInput) {\r
 +            onUrlInputFocusChanged((TextView) view, hasFocus);\r
              \r
 -            accManager.setUserData(account,\r
 -                    AccountAuthenticator.KEY_OC_BASE_URL, mBaseUrl);\r
 -\r
 -            setAccountAuthenticatorResult(intent.getExtras());\r
 -            setResult(RESULT_OK, intent);\r
 -            Bundle bundle = new Bundle();\r
 -            bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);\r
 -            //getContentResolver().startSync(ProviderTableMeta.CONTENT_URI,\r
 -            //        bundle);\r
 -            ContentResolver.requestSync(account, "org.owncloud", bundle);\r
 -\r
 -            /*\r
 -             * if\r
 -             * (mConnChkRunnable.getDiscoveredVersion().compareTo(OwnCloudVersion\r
 -             * .owncloud_v2) >= 0) { Intent i = new Intent(this,\r
 -             * ExtensionsAvailableActivity.class); startActivity(i); }\r
 -             */\r
 +        } else if (view.getId() == R.id.account_password) {\r
 +            onPasswordFocusChanged((TextView) view, hasFocus);\r
 +        }\r
 +    }\r
 +    \r
  \r
 -            finish();\r
 +    /**\r
 +     * Handles changes in focus on the text input for the server URL.\r
 +     * \r
 +     * IMPORTANT ENTRY POINT 2: When (!hasFocus), user wrote the server URL and changed to \r
 +     * other field. The operation to check the existence of the server in the entered URL is\r
 +     * started. \r
 +     * \r
 +     * When hasFocus:    user 'comes back' to write again the server URL.\r
 +     * \r
 +     * @param hostInput     TextView with the URL input field receiving the change of focus.\r
 +     * @param hasFocus      'True' if focus is received, 'false' if is lost\r
 +     */\r
 +    private void onUrlInputFocusChanged(TextView hostInput, boolean hasFocus) {\r
 +        if (!hasFocus) {\r
 +            checkOcServer();\r
 +            \r
          } else {\r
 -            try {\r
 -                dismissDialog(DIALOG_LOGIN_PROGRESS);\r
 -            } catch (IllegalArgumentException e) {\r
 -                // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens\r
 -            }\r
 -            TextView tv = (TextView) findViewById(R.id.account_username);\r
 -            tv.setError(message + "        ");  // the extra spaces are a workaround for an ugly bug: \r
 -                                                // 1. insert wrong credentials and connect\r
 -                                                // 2. put the focus on the user name field with using hardware controls (don't touch the screen); the error is shown UNDER the field\r
 -                                                // 3. touch the user name field; the software keyboard appears; the error popup is moved OVER the field and SHRINKED in width, losing the last word\r
 -                                                // Seen, at least, in Android 2.x devices\r
 +            // avoids that the 'connect' button can be clicked if the test was previously passed\r
 +            mOkButton.setEnabled(false); \r
 +        }\r
 +    }\r
 +\r
 +\r
 +    private void checkOcServer() {\r
 +        String uri = mHostUrlInput.getText().toString().trim();\r
 +        if (uri.length() != 0) {\r
 +            mStatusText = R.string.auth_testing_connection;\r
 +            mStatusIcon = R.drawable.progress_small;\r
 +            updateConnStatus();\r
 +            /** TODO cancel previous connection check if the user tries to ammend a wrong URL  \r
 +            if(mConnChkOperation != null) {\r
 +                mConnChkOperation.cancel();\r
 +            } */\r
 +            mOcServerChkOperation = new  OwnCloudServerCheckOperation(uri, this);\r
 +            WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this);\r
 +            mHostBaseUrl = "";\r
 +            mDiscoveredVersion = null;\r
 +            mOperationThread = mOcServerChkOperation.execute(client, this, mHandler);\r
 +        } else {\r
 +            mRefreshButton.setVisibility(View.INVISIBLE);\r
 +            mStatusText = 0;\r
 +            mStatusIcon = 0;\r
 +            updateConnStatus();\r
          }\r
      }\r
 +\r
 +\r
 +    /**\r
 +     * Handles changes in focus on the text input for the password (basic authorization).\r
 +     * \r
 +     * When (hasFocus), the button to toggle password visibility is shown.\r
 +     * \r
 +     * When (!hasFocus), the button is made invisible and the password is hidden.\r
 +     * \r
 +     * @param passwordInput    TextView with the password input field receiving the change of focus.\r
 +     * @param hasFocus          'True' if focus is received, 'false' if is lost\r
 +     */\r
 +    private void onPasswordFocusChanged(TextView passwordInput, boolean hasFocus) {\r
 +        if (hasFocus) {\r
 +            mViewPasswordButton.setVisibility(View.VISIBLE);\r
 +        } else {\r
 +            int input_type = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD;\r
 +            passwordInput.setInputType(input_type);\r
 +            mViewPasswordButton.setVisibility(View.INVISIBLE);\r
 +        }\r
 +    }\r
 +\r
 +\r
 +    \r
 +    /**\r
 +     * Cancels the authenticator activity\r
 +     * \r
 +     * IMPORTANT ENTRY POINT 3: Never underestimate the importance of cancellation\r
 +     * \r
 +     * This method is bound in the layout/acceoun_setup.xml resource file.\r
 +     * \r
 +     * @param view      Cancel button\r
 +     */\r
      public void onCancelClick(View view) {\r
 -        setResult(RESULT_CANCELED);\r
 +        setResult(RESULT_CANCELED);     // TODO review how is this related to AccountAuthenticator\r
          finish();\r
      }\r
      \r
 +    \r
 +    \r
 +    /**\r
 +     * Checks the credentials of the user in the root of the ownCloud server\r
 +     * before creating a new local account.\r
 +     * \r
 +     * For basic authorization, a check of existence of the root folder is\r
 +     * performed.\r
 +     * \r
 +     * For OAuth, starts the flow to get an access token; the credentials test \r
 +     * is postponed until it is available.\r
 +     * \r
 +     * IMPORTANT ENTRY POINT 4\r
 +     * \r
 +     * @param view      OK button\r
 +     */\r
      public void onOkClick(View view) {\r
 -        String prefix = "";\r
 -        String url = ((TextView) findViewById(R.id.host_URL)).getText()\r
 -                .toString().trim();\r
 -        if (mIsSslConn) {\r
 -            prefix = "https://";\r
 -        } else {\r
 -            prefix = "http://";\r
 +        // this check should be unnecessary\r
 +        if (mDiscoveredVersion == null || !mDiscoveredVersion.isVersionValid()  || mHostBaseUrl == null || mHostBaseUrl.length() == 0) {\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_wtf_reenter_URL;\r
 +            updateConnStatus();\r
 +            mOkButton.setEnabled(false);\r
 +            Log.wtf(TAG,  "The user was allowed to click 'connect' to an unchecked server!!");\r
 +            return;\r
          }\r
 -        if (url.toLowerCase().startsWith("http://")\r
 -                || url.toLowerCase().startsWith("https://")) {\r
 -            prefix = "";\r
 +        \r
 +        if (mOAuth2Check.isChecked()) {\r
 +            startOauthorization();\r
 +            \r
 +        } else {\r
 +            checkBasicAuthorization();\r
          }\r
 -        continueConnection(prefix);\r
      }\r
      \r
 -    public void onRegisterClick(View view) {\r
 -        Intent register = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_account_register)));\r
 -        setResult(RESULT_CANCELED);\r
 -        startActivity(register);\r
 +    \r
 +    /**\r
 +     * Tests the credentials entered by the user performing a check of existence on \r
 +     * the root folder of the ownCloud server.\r
 +     */\r
 +    private void checkBasicAuthorization() {\r
 +        /// get the path to the root folder through WebDAV from the version server\r
 +        String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, false);\r
 +        \r
 +        /// get basic credentials entered by user\r
 +        String username = mUsernameInput.getText().toString();\r
 +        String password = mPasswordInput.getText().toString();\r
 +        \r
 +        /// be gentle with the user\r
 +        showDialog(DIALOG_LOGIN_PROGRESS);\r
 +        \r
 +        /// test credentials accessing the root folder\r
 +        mAuthCheckOperation = new  ExistenceCheckOperation("", this, false);\r
 +        WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this);\r
 +        client.setBasicCredentials(username, password);\r
 +        mOperationThread = mAuthCheckOperation.execute(client, this, mHandler);\r
      }\r
  \r
 -    private void continueConnection(String prefix) {\r
 -        String url = ((TextView) findViewById(R.id.host_URL)).getText()\r
 -                .toString().trim();\r
 -        String username = ((TextView) findViewById(R.id.account_username))\r
 -                .getText().toString();\r
 -        String password = ((TextView) findViewById(R.id.account_password))\r
 -                .getText().toString();\r
 -        if (url.endsWith("/"))\r
 -            url = url.substring(0, url.length() - 1);\r
 -\r
 -        URL uri = null;\r
 -        String webdav_path = AccountUtils.getWebdavPath(mConnChkRunnable\r
 -                .getDiscoveredVersion());\r
 -        \r
 -        if (webdav_path == null) {\r
 -            onAuthenticationResult(false, getString(R.string.auth_bad_oc_version_title));\r
 -            return;\r
 -        }\r
 +\r
 +    /**\r
 +     * Starts the OAuth 'grant type' flow to get an access token, with \r
 +     * a GET AUTHORIZATION request to the BUILT-IN authorization server. \r
 +     */\r
 +    private void startOauthorization() {\r
 +        // be gentle with the user\r
 +        mStatusIcon = R.drawable.progress_small;\r
 +        mStatusText = R.string.oauth_login_connection;\r
 +        updateAuthStatus();\r
          \r
 -        try {\r
 -            mBaseUrl = prefix + url;\r
 -            String url_str = prefix + url + webdav_path;\r
 -            uri = new URL(url_str);\r
 -        } catch (MalformedURLException e) {\r
 -            // should never happen\r
 -            onAuthenticationResult(false, getString(R.string.auth_incorrect_address_title));\r
 -            return;\r
 +        // GET AUTHORIZATION request\r
 +        /*\r
 +        mOAuth2GetCodeRunnable = new OAuth2GetAuthorizationToken(, this);\r
 +        mOAuth2GetCodeRunnable.setListener(this, mHandler);\r
 +        mOAuth2GetCodeThread = new Thread(mOAuth2GetCodeRunnable);\r
 +        mOAuth2GetCodeThread.start();\r
 +        */\r
 +        \r
 +        //if (mGrantType.equals(OAuth2Context.OAUTH2_AUTH_CODE_GRANT_TYPE)) {\r
 +        Uri uri = Uri.parse(getString(R.string.oauth_url_endpoint_auth));\r
 +        Uri.Builder uriBuilder = uri.buildUpon();\r
 +        uriBuilder.appendQueryParameter(OAuth2Context.CODE_RESPONSE_TYPE, OAuth2Context.OAUTH2_CODE_RESPONSE_TYPE);\r
 +        uriBuilder.appendQueryParameter(OAuth2Context.CODE_REDIRECT_URI, OAuth2Context.MY_REDIRECT_URI);   \r
 +        uriBuilder.appendQueryParameter(OAuth2Context.CODE_CLIENT_ID, OAuth2Context.OAUTH2_F_CLIENT_ID);\r
 +        uriBuilder.appendQueryParameter(OAuth2Context.CODE_SCOPE, OAuth2Context.OAUTH2_F_SCOPE);\r
 +        //uriBuilder.appendQueryParameter(OAuth2Context.CODE_STATE, whateverwewant);\r
 +        uri = uriBuilder.build();\r
 +        Log.d(TAG, "Starting browser to view " + uri.toString());\r
 +        Intent i = new Intent(Intent.ACTION_VIEW, uri);\r
 +        startActivity(i);\r
 +        //}\r
 +    }\r
 +\r
 +    \r
 +    /**\r
 +     * Callback method invoked when a RemoteOperation executed by this Activity finishes.\r
 +     * \r
 +     * Dispatches the operation flow to the right method.\r
 +     */\r
 +    @Override\r
 +    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {\r
 +\r
 +        if (operation instanceof OwnCloudServerCheckOperation) {\r
 +            onOcServerCheckFinish((OwnCloudServerCheckOperation) operation, result);\r
 +            \r
 +        } else if (operation instanceof OAuth2GetAccessToken) {\r
 +            onGetOAuthAccessTokenFinish((OAuth2GetAccessToken)operation, result);\r
 +                \r
 +        } else if (operation instanceof ExistenceCheckOperation)  {\r
 +            onAuthorizationCheckFinish((ExistenceCheckOperation)operation, result);\r
 +                \r
          }\r
 +    }\r
 +    \r
  \r
 -        showDialog(DIALOG_LOGIN_PROGRESS);\r
 -        mAuthRunnable = new AuthenticationRunnable(uri, username, password, this);\r
 -        mAuthRunnable.setOnAuthenticationResultListener(this, mHandler);\r
 -        mAuthThread = new Thread(mAuthRunnable);\r
 -        mAuthThread.start();\r
 +    /**\r
 +     * Processes the result of the server check performed when the user finishes the enter of the\r
 +     * server URL.\r
 +     * \r
 +     * @param operation     Server check performed.\r
 +     * @param result        Result of the check.\r
 +     */\r
 +    private void onOcServerCheckFinish(OwnCloudServerCheckOperation operation, RemoteOperationResult result) {\r
 +        /// update status icon and text\r
 +        updateStatusIconAndText(result);\r
 +        updateConnStatus();\r
 +\r
 +        /// save result state\r
 +        mStatusCorrect = result.isSuccess();\r
 +        mIsSslConn = (result.getCode() == ResultCode.OK_SSL);\r
 +        \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
 +            mLastSslUntrustedServerResult = result;\r
 +            showDialog(DIALOG_SSL_VALIDATOR); \r
 +        }\r
 +        \r
 +        /// update the visibility of the 'retry connection' button\r
 +        if (!mStatusCorrect)\r
 +            mRefreshButton.setVisibility(View.VISIBLE);\r
 +        else\r
 +            mRefreshButton.setVisibility(View.INVISIBLE);\r
 +        \r
 +        /// retrieve discovered version and normalize server URL\r
 +        mDiscoveredVersion = operation.getDiscoveredVersion();\r
 +        mHostBaseUrl = mHostUrlInput.getText().toString().trim();\r
 +        if (!mHostBaseUrl.toLowerCase().startsWith("http://") &&\r
 +            !mHostBaseUrl.toLowerCase().startsWith("https://")) {\r
 +            \r
 +            if (mIsSslConn) {\r
 +                mHostBaseUrl = "https://" + mHostBaseUrl;\r
 +            } else {\r
 +                mHostBaseUrl = "http://" + mHostBaseUrl;\r
 +            }\r
 +            \r
 +        }\r
 +        if (mHostBaseUrl.endsWith("/"))\r
 +            mHostBaseUrl = mHostBaseUrl.substring(0, mHostBaseUrl.length() - 1);\r
 +        \r
 +        /// allow or not the user try to access the server\r
 +        mOkButton.setEnabled(mStatusCorrect);\r
      }\r
  \r
 -    @Override\r
 -    public void onConnectionCheckResult(ResultType type) {\r
 +\r
 +    /**\r
 +     * Chooses the right icon and text to show to the user for the received operation result.\r
 +     * \r
 +     * @param result    Result of a remote operation performed in this activity\r
 +     */\r
 +    private void updateStatusIconAndText(RemoteOperationResult result) {\r
          mStatusText = mStatusIcon = 0;\r
 -        mStatusCorrect = false;\r
 -        String t_url = ((TextView) findViewById(R.id.host_URL)).getText()\r
 -                .toString().trim().toLowerCase();\r
  \r
 -        switch (type) {\r
 +        switch (result.getCode()) {\r
          case OK_SSL:\r
 -            mIsSslConn = true;\r
              mStatusIcon = android.R.drawable.ic_secure;\r
              mStatusText = R.string.auth_secure_connection;\r
 -            mStatusCorrect = true;\r
              break;\r
 +            \r
          case OK_NO_SSL:\r
 -            mIsSslConn = false;\r
 -            mStatusCorrect = true;\r
 -            if (t_url.startsWith("http://") ) {\r
 +        case OK:\r
 +            if (mHostUrlInput.getText().toString().trim().toLowerCase().startsWith("http://") ) {\r
                  mStatusText = R.string.auth_connection_established;\r
                  mStatusIcon = R.drawable.ic_ok;\r
              } else {\r
                  mStatusIcon = android.R.drawable.ic_partial_secure;\r
              }\r
              break;\r
 +            \r
 +        case SSL_RECOVERABLE_PEER_UNVERIFIED:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_ssl_unverified_server_title;\r
 +            break;\r
 +                \r
          case BAD_OC_VERSION:\r
              mStatusIcon = R.drawable.common_error;\r
              mStatusText = R.string.auth_bad_oc_version_title;\r
              mStatusIcon = R.drawable.common_error;\r
              mStatusText = R.string.auth_incorrect_address_title;\r
              break;\r
 -        case SSL_UNVERIFIED_SERVER:\r
 +            \r
 +        case SSL_ERROR:\r
              mStatusIcon = R.drawable.common_error;\r
 -            mStatusText = R.string.auth_ssl_unverified_server_title;\r
 +            mStatusText = R.string.auth_ssl_general_error_title;\r
              break;\r
 -        case SSL_INIT_ERROR:\r
 +            \r
 +        case UNAUTHORIZED:\r
              mStatusIcon = R.drawable.common_error;\r
 -            mStatusText = R.string.auth_ssl_general_error_title;\r
 +            mStatusText = R.string.auth_unauthorized;\r
              break;\r
          case HOST_NOT_AVAILABLE:\r
              mStatusIcon = R.drawable.common_error;\r
              mStatusIcon = R.drawable.common_error;\r
              mStatusText = R.string.auth_not_configured_title;\r
              break;\r
 +        case FILE_NOT_FOUND:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_incorrect_path_title;\r
 +            break;\r
 +        case OAUTH2_ERROR:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_oauth_error;\r
 +            break;\r
 +        case OAUTH2_ERROR_ACCESS_DENIED:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_oauth_error_access_denied;\r
 +            break;\r
 +        case UNHANDLED_HTTP_CODE:\r
          case UNKNOWN_ERROR:\r
              mStatusIcon = R.drawable.common_error;\r
              mStatusText = R.string.auth_unknown_error_title;\r
              break;\r
 -        case FILE_NOT_FOUND:\r
 -            mStatusIcon = R.drawable.common_error;\r
 -            mStatusText = R.string.auth_incorrect_path_title;\r
 +            \r
 +        default:\r
              break;\r
 +        }\r
 +    }\r
 +\r
 +\r
 +    /**\r
 +     * Processes the result of the request for and access token send \r
 +     * to an OAuth authorization server.\r
 +     * \r
 +     * @param operation     Operation performed requesting the access token.\r
 +     * @param result        Result of the operation.\r
 +     */\r
 +    private void onGetOAuthAccessTokenFinish(OAuth2GetAccessToken operation, RemoteOperationResult result) {\r
 +        try {\r
 +            dismissDialog(DIALOG_OAUTH2_LOGIN_PROGRESS);\r
 +        } catch (IllegalArgumentException e) {\r
 +            // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens\r
 +        }\r
 +\r
 +        String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, true);\r
 +        if (result.isSuccess() && webdav_path != null) {\r
 +            /// be gentle with the user\r
 +            showDialog(DIALOG_LOGIN_PROGRESS);\r
 +            \r
 +            /// time to test the retrieved access token on the ownCloud server\r
 +            mOAuthAccessToken = ((OAuth2GetAccessToken)operation).getResultTokenMap().get(OAuth2Context.KEY_ACCESS_TOKEN);\r
 +            Log.d(TAG, "Got ACCESS TOKEN: " + mOAuthAccessToken);\r
 +            mAuthCheckOperation = new ExistenceCheckOperation("", this, false);\r
 +            WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this);\r
 +            client.setBearerCredentials(mOAuthAccessToken);\r
 +            mAuthCheckOperation.execute(client, this, mHandler);\r
 +            \r
 +        } else {\r
 +            updateStatusIconAndText(result);\r
 +            updateAuthStatus();\r
 +            Log.d(TAG, "Access failed: " + result.getLogMessage());\r
 +        }\r
 +    }\r
 +\r
 +    \r
 +    /**\r
 +     * Processes the result of the access check performed to try the user credentials.\r
 +     * \r
 +     * Creates a new account through the AccountManager.\r
 +     * \r
 +     * @param operation     Access check performed.\r
 +     * @param result        Result of the operation.\r
 +     */\r
 +    private void onAuthorizationCheckFinish(ExistenceCheckOperation operation, RemoteOperationResult result) {\r
 +        try {\r
 +            dismissDialog(DIALOG_LOGIN_PROGRESS);\r
 +        } catch (IllegalArgumentException e) {\r
 +            // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens\r
 +        }\r
 +        \r
 +        if (result.isSuccess()) {\r
 +            Log.d(TAG, "Successful access - time to save the account");\r
 +\r
 +            if (mAction == ACTION_CREATE) {\r
 +                createAccount();\r
 +                \r
 +            } else {\r
 +                updateToken();\r
 +            }\r
 +            \r
 +            finish();\r
 +            \r
 +        } else {\r
 +            updateStatusIconAndText(result);\r
 +            updateAuthStatus();\r
 +            Log.d(TAG, "Access failed: " + result.getLogMessage());\r
 +        }\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
 +     */\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
 +        boolean isOAuth = mOAuth2Check.isChecked();\r
 +        if (isOAuth) {\r
 +            response.putString(AccountManager.KEY_AUTHTOKEN, mOAuthAccessToken);\r
 +            // the next line is necessary; by now, notifications are calling directly to the AuthenticatorActivity to update, without AccountManager intervention\r
 +            mAccountMgr.setAuthToken(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, mOAuthAccessToken);\r
 +        } else {\r
 +            response.putString(AccountManager.KEY_AUTHTOKEN, mPasswordInput.getText().toString());\r
 +            mAccountMgr.setPassword(mAccount, mPasswordInput.getText().toString());\r
 +        }\r
 +        setAccountAuthenticatorResult(response);\r
 +    }\r
 +\r
 +\r
 +    /**\r
 +     * Creates a new account through the Account Authenticator that started this activity. \r
 +     * \r
 +     * This makes the account permanent.\r
 +     * \r
 +     * TODO Decide how to name the OAuth accounts\r
 +     * TODO Minimize the direct interactions with the account manager; seems that not all the operations \r
 +     * in the current code are really necessary, provided that right extras are returned to the Account\r
 +     * Authenticator through setAccountAuthenticatorResult  \r
 +     */\r
 +    private void createAccount() {\r
 +        /// create and save new ownCloud account\r
 +        boolean isOAuth = mOAuth2Check.isChecked();\r
 +        \r
 +        Uri uri = Uri.parse(mHostBaseUrl);\r
 +        String username = mUsernameInput.getText().toString().trim();\r
 +        if (isOAuth) {\r
 +            username = "OAuth_user" + (new java.util.Random(System.currentTimeMillis())).nextLong();    // TODO change this to something readable\r
 +        }            \r
 +        String accountName = username + "@" + uri.getHost();\r
 +        if (uri.getPort() >= 0) {\r
 +            accountName += ":" + uri.getPort();\r
 +        }\r
 +        mAccount = new Account(accountName, AccountAuthenticator.ACCOUNT_TYPE);\r
 +        if (isOAuth) {\r
 +            mAccountMgr.addAccountExplicitly(mAccount, "", null);  // with our implementation, the password is never input in the app\r
 +        } else {\r
 +            mAccountMgr.addAccountExplicitly(mAccount, mPasswordInput.getText().toString(), null);\r
 +        }\r
 +\r
 +        /// add the new account as default in preferences, if there is none already\r
 +        Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this);\r
 +        if (defaultAccount == null) {\r
 +            SharedPreferences.Editor editor = PreferenceManager\r
 +                    .getDefaultSharedPreferences(this).edit();\r
 +            editor.putString("select_oc_account", accountName);\r
 +            editor.commit();\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
 +        final Intent intent = new Intent();       \r
 +        intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE,    AccountAuthenticator.ACCOUNT_TYPE);\r
 +        intent.putExtra(AccountManager.KEY_ACCOUNT_NAME,    mAccount.name);\r
 +        if (!isOAuth)\r
 +            intent.putExtra(AccountManager.KEY_AUTHTOKEN,   AccountAuthenticator.ACCOUNT_TYPE); // TODO check this; not sure it's right; maybe\r
 +        intent.putExtra(AccountManager.KEY_USERDATA,        username);\r
 +        if (isOAuth) {\r
 +            mAccountMgr.setAuthToken(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, mOAuthAccessToken);\r
 +        }\r
 +        /// add user data to the new account; TODO probably can be done in the last parameter addAccountExplicitly, or in KEY_USERDATA\r
 +        mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION,    mDiscoveredVersion.toString());\r
 +        mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL,   mHostBaseUrl);\r
 +        if (isOAuth)\r
 +            mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_OAUTH2, "TRUE");  // TODO this flag should be unnecessary\r
 +    \r
 +        setAccountAuthenticatorResult(intent.getExtras());\r
 +        setResult(RESULT_OK, intent);\r
 +        \r
 +        /// immediately request for the synchronization of the new account\r
 +        Bundle bundle = new Bundle();\r
 +        bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);\r
 +        ContentResolver.requestSync(mAccount, AccountAuthenticator.AUTHORITY, bundle);\r
 +    }\r
 +\r
 +\r
 +    /**\r
 +     * {@inheritDoc}\r
 +     * \r
 +     * Necessary to update the contents of the SSL Dialog\r
 +     * \r
 +     * TODO move to some common place for all possible untrusted SSL failures\r
 +     */\r
 +    @Override\r
 +    protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {\r
 +        switch (id) {\r
 +        case DIALOG_LOGIN_PROGRESS:\r
 +        case DIALOG_CERT_NOT_SAVED:\r
 +        case DIALOG_OAUTH2_LOGIN_PROGRESS:\r
 +            break;\r
 +        case DIALOG_SSL_VALIDATOR: {\r
 +            ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);\r
 +            break;\r
 +        }\r
          default:\r
 -            Log.e(TAG, "Incorrect connection checker result type: " + type);\r
 +            Log.e(TAG, "Incorrect dialog called with id = " + id);\r
          }\r
 -        setResultIconAndText(mStatusIcon, mStatusText);\r
 -        if (!mStatusCorrect)\r
 -            findViewById(R.id.refreshButton).setVisibility(View.VISIBLE);\r
 -        else\r
 -            findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE);\r
 -        findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);\r
      }\r
  \r
 +    \r
 +    /**\r
 +     * {@inheritDoc}\r
 +     */\r
      @Override\r
 -    public void onFocusChange(View view, boolean hasFocus) {\r
 -        if (view.getId() == R.id.host_URL) {\r
 -            if (!hasFocus) {\r
 -                TextView tv = ((TextView) findViewById(R.id.host_URL));\r
 -                String uri = tv.getText().toString().trim();\r
 -                if (uri.length() != 0) {\r
 -                    setResultIconAndText(R.drawable.progress_small,\r
 -                            R.string.auth_testing_connection);\r
 -                    //mConnChkRunnable = new ConnectionCheckerRunnable(uri, this);\r
 -                    mConnChkRunnable = new ConnectionCheckOperation(uri, this);\r
 -                    //mConnChkRunnable.setListener(this, mHandler);\r
 -                    //mAuthThread = new Thread(mConnChkRunnable);\r
 -                    //mAuthThread.start();\r
 -                      WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this);\r
 -                    mAuthThread = mConnChkRunnable.execute(client, this, mHandler);\r
 -                } else {\r
 -                    findViewById(R.id.refreshButton).setVisibility(\r
 -                            View.INVISIBLE);\r
 -                    setResultIconAndText(0, 0);\r
 +    protected Dialog onCreateDialog(int id) {\r
 +        Dialog dialog = null;\r
 +        switch (id) {\r
 +        case DIALOG_LOGIN_PROGRESS: {\r
 +            /// simple progress dialog\r
 +            ProgressDialog working_dialog = new ProgressDialog(this);\r
 +            working_dialog.setMessage(getResources().getString(R.string.auth_trying_to_login));\r
 +            working_dialog.setIndeterminate(true);\r
 +            working_dialog.setCancelable(true);\r
 +            working_dialog\r
 +                    .setOnCancelListener(new DialogInterface.OnCancelListener() {\r
 +                        @Override\r
 +                        public void onCancel(DialogInterface dialog) {\r
 +                            /// TODO study if this is enough\r
 +                            Log.i(TAG, "Login canceled");\r
 +                            if (mOperationThread != null) {\r
 +                                mOperationThread.interrupt();\r
 +                                finish();\r
 +                            }\r
 +                        }\r
 +                    });\r
 +            dialog = working_dialog;\r
 +            break;\r
 +        }\r
 +        case DIALOG_OAUTH2_LOGIN_PROGRESS: {\r
 +            /// oAuth2 dialog. We show here to the user the URL and user_code that the user must validate in a web browser. - OLD!\r
 +            // TODO optimize this dialog\r
 +            ProgressDialog working_dialog = new ProgressDialog(this);\r
 +            /* Leave the old OAuth flow\r
 +            try {\r
 +                if (mCodeResponseJson != null && mCodeResponseJson.has(OAuth2GetCodeRunnable.CODE_VERIFICATION_URL)) {\r
 +                    working_dialog.setMessage(String.format(getString(R.string.oauth_code_validation_message), \r
 +                            mCodeResponseJson.getString(OAuth2GetCodeRunnable.CODE_VERIFICATION_URL), \r
 +                            mCodeResponseJson.getString(OAuth2GetCodeRunnable.CODE_USER_CODE)));\r
 +                } else {*/\r
 +                    working_dialog.setMessage(String.format("Getting authorization")); \r
 +                /*}\r
 +            } catch (JSONException e) {\r
 +                Log.e(TAG, "onCreateDialog->JSONException: " + e.toString());\r
 +            }*/\r
 +            working_dialog.setIndeterminate(true);\r
 +            working_dialog.setCancelable(true);\r
 +            working_dialog\r
 +            .setOnCancelListener(new DialogInterface.OnCancelListener() {\r
 +                @Override\r
 +                public void onCancel(DialogInterface dialog) {\r
 +                    Log.i(TAG, "Login canceled");\r
 +                    /*if (mOAuth2GetCodeThread != null) {\r
 +                        mOAuth2GetCodeThread.interrupt();\r
 +                        finish();\r
 +                    } */\r
 +                    /*if (tokenReceiver != null) {\r
 +                        unregisterReceiver(tokenReceiver);\r
 +                        tokenReceiver = null;\r
 +                        finish();\r
 +                    }*/\r
 +                    finish();\r
                  }\r
 -            } else {\r
 -                // avoids that the 'connect' button can be clicked if the test was previously passed\r
 -                findViewById(R.id.buttonOK).setEnabled(false); \r
 -            }\r
 -        } else if (view.getId() == R.id.account_password) {\r
 -            ImageView iv = (ImageView) findViewById(R.id.viewPassword);\r
 -            if (hasFocus) {\r
 -                iv.setVisibility(View.VISIBLE);\r
 -            } else {\r
 -                TextView v = (TextView) findViewById(R.id.account_password);\r
 -                int input_type = InputType.TYPE_CLASS_TEXT\r
 -                        | InputType.TYPE_TEXT_VARIATION_PASSWORD;\r
 -                v.setInputType(input_type);\r
 -                iv.setVisibility(View.INVISIBLE);\r
 -            }\r
 +            });\r
 +            dialog = working_dialog;\r
 +            break;\r
          }\r
 +        case DIALOG_SSL_VALIDATOR: {\r
 +            /// TODO start to use new dialog interface, at least for this (it is a FragmentDialog already)\r
 +            dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);\r
 +            break;\r
 +        }\r
 +        case DIALOG_CERT_NOT_SAVED: {\r
 +            AlertDialog.Builder builder = new AlertDialog.Builder(this);\r
 +            builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));\r
 +            builder.setCancelable(false);\r
 +            builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {\r
 +                    @Override\r
 +                    public void onClick(DialogInterface dialog, int which) {\r
 +                        dialog.dismiss();\r
 +                    };\r
 +                });\r
 +            dialog = builder.create();\r
 +            break;\r
 +        }\r
 +        default:\r
 +            Log.e(TAG, "Incorrect dialog called with id = " + id);\r
 +        }\r
 +        return dialog;\r
 +    }\r
 +\r
 +    \r
 +    /**\r
 +     * Starts and activity to open the 'new account' page in the ownCloud web site\r
 +     * \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.url_account_register)));\r
 +        setResult(RESULT_CANCELED);\r
 +        startActivity(register);\r
      }\r
  \r
 -    private void setResultIconAndText(int drawable_id, int text_id) {\r
 +    \r
 +    /**\r
 +     * Updates the content and visibility state of the icon and text associated\r
 +     * to the last check on the ownCloud server.\r
 +     */\r
 +    private void updateConnStatus() {\r
          ImageView iv = (ImageView) findViewById(R.id.action_indicator);\r
          TextView tv = (TextView) findViewById(R.id.status_text);\r
  \r
 -        if (drawable_id == 0 && text_id == 0) {\r
 +        if (mStatusIcon == 0 && mStatusText == 0) {\r
              iv.setVisibility(View.INVISIBLE);\r
              tv.setVisibility(View.INVISIBLE);\r
          } else {\r
 -            iv.setImageResource(drawable_id);\r
 -            tv.setText(text_id);\r
 +            iv.setImageResource(mStatusIcon);\r
 +            tv.setText(mStatusText);\r
              iv.setVisibility(View.VISIBLE);\r
              tv.setVisibility(View.VISIBLE);\r
          }\r
      }\r
 +    \r
 +    \r
 +    /**\r
 +     * Updates the content and visibility state of the icon and text associated\r
 +     * to the interactions with the OAuth authorization server.\r
 +     */\r
 +    private void updateAuthStatus() {\r
 +        /*ImageView iv = (ImageView) findViewById(R.id.auth_status_icon);\r
 +        TextView tv = (TextView) findViewById(R.id.auth_status_text);*/\r
 +\r
 +        if (mStatusIcon == 0 && mStatusText == 0) {\r
 +            mAuthStatusLayout.setVisibility(View.INVISIBLE);\r
 +            /*iv.setVisibility(View.INVISIBLE);\r
 +            tv.setVisibility(View.INVISIBLE);*/\r
 +        } else {\r
 +            mAuthStatusLayout.setText(mStatusText);\r
 +            mAuthStatusLayout.setCompoundDrawablesWithIntrinsicBounds(mStatusIcon, 0, 0, 0);\r
 +            /*iv.setImageResource(mStatusIcon);\r
 +            tv.setText(mStatusText);\r
 +            /*iv.setVisibility(View.VISIBLE);\r
 +            tv.setVisibility(View.VISIBLE);^*/\r
 +            mAuthStatusLayout.setVisibility(View.VISIBLE);\r
 +        }\r
 +    }     \r
  \r
 +    \r
 +    /**\r
 +     * Called when the refresh button in the input field for ownCloud host is clicked.\r
 +     * \r
 +     * Performs a new check on the URL in the input field.\r
 +     * \r
 +     * @param view      Refresh 'button'\r
 +     */\r
 +    public void onRefreshClick(View view) {\r
 +        onFocusChange(mRefreshButton, false);\r
 +    }\r
 +    \r
 +    \r
 +    /**\r
 +     * Called when the eye icon in the password field is clicked.\r
 +     * \r
 +     * Toggles the visibility of the password in the field. \r
 +     * \r
 +     * @param view      'View password' 'button'\r
 +     */\r
 +    public void onViewPasswordClick(View view) {\r
 +        int selectionStart = mPasswordInput.getSelectionStart();\r
 +        int selectionEnd = mPasswordInput.getSelectionEnd();\r
 +        int input_type = mPasswordInput.getInputType();\r
 +        if ((input_type & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {\r
 +            input_type = InputType.TYPE_CLASS_TEXT\r
 +                    | InputType.TYPE_TEXT_VARIATION_PASSWORD;\r
 +        } else {\r
 +            input_type = InputType.TYPE_CLASS_TEXT\r
 +                    | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;\r
 +        }\r
 +        mPasswordInput.setInputType(input_type);\r
 +        mPasswordInput.setSelection(selectionStart, selectionEnd);\r
 +    }    \r
 +    \r
 +    \r
 +    /**\r
 +     * Called when the checkbox for OAuth authorization is clicked.\r
 +     * \r
 +     * Hides or shows the input fields for user & password. \r
 +     * \r
 +     * @param view      'View password' 'button'\r
 +     */\r
 +    public void onCheckClick(View view) {\r
 +        CheckBox oAuth2Check = (CheckBox)view;      \r
 +        changeViewByOAuth2Check(oAuth2Check.isChecked());\r
 +\r
 +    }\r
 +    \r
 +    /**\r
 +     * Changes the visibility of input elements depending upon the kind of authorization\r
 +     * chosen by the user: basic or OAuth\r
 +     * \r
 +     * @param checked       'True' when OAuth is selected.\r
 +     */\r
 +    public void changeViewByOAuth2Check(Boolean checked) {\r
 +        \r
 +        if (checked) {\r
 +            mOAuthAuthEndpointText.setVisibility(View.VISIBLE);\r
 +            mOAuthTokenEndpointText.setVisibility(View.VISIBLE);\r
 +            mUsernameInput.setVisibility(View.GONE);\r
 +            mPasswordInput.setVisibility(View.GONE);\r
 +            mViewPasswordButton.setVisibility(View.GONE);\r
 +        } else {\r
 +            mOAuthAuthEndpointText.setVisibility(View.GONE);\r
 +            mOAuthTokenEndpointText.setVisibility(View.GONE);\r
 +            mUsernameInput.setVisibility(View.VISIBLE);\r
 +            mPasswordInput.setVisibility(View.VISIBLE);\r
 +            mViewPasswordButton.setVisibility(View.INVISIBLE);\r
 +        }     \r
 +\r
 +    }    \r
 +    \r
 +    /* Leave the old OAuth flow\r
 +    // Results from the first call to oAuth2 server : getting the user_code and verification_url.\r
      @Override\r
 -    public void onClick(View v) {\r
 -        if (v.getId() == R.id.refreshButton) {\r
 -            onFocusChange(findViewById(R.id.host_URL), false);\r
 -        } else if (v.getId() == R.id.viewPassword) {\r
 -            EditText view = (EditText) findViewById(R.id.account_password);\r
 -            int selectionStart = view.getSelectionStart();\r
 -            int selectionEnd = view.getSelectionEnd();\r
 -            int input_type = view.getInputType();\r
 -            if ((input_type & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {\r
 -                input_type = InputType.TYPE_CLASS_TEXT\r
 -                        | InputType.TYPE_TEXT_VARIATION_PASSWORD;\r
 -            } else {\r
 -                input_type = InputType.TYPE_CLASS_TEXT\r
 -                        | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;\r
 -            }\r
 -            view.setInputType(input_type);\r
 -            view.setSelection(selectionStart, selectionEnd);\r
 +    public void onOAuth2GetCodeResult(ResultOAuthType type, JSONObject responseJson) {\r
 +        if ((type == ResultOAuthType.OK_SSL)||(type == ResultOAuthType.OK_NO_SSL)) {\r
 +            mCodeResponseJson = responseJson;\r
 +            if (mCodeResponseJson != null) {\r
 +                getOAuth2AccessTokenFromJsonResponse();\r
 +            }  // else - nothing to do here - wait for callback !!!\r
 +        \r
 +        } else if (type == ResultOAuthType.HOST_NOT_AVAILABLE) {\r
 +            updateOAuth2IconAndText(R.drawable.common_error, R.string.oauth_connection_url_unavailable);\r
          }\r
      }\r
  \r
 -      @Override\r
 -      public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {\r
 -              if (operation.equals(mConnChkRunnable)) {\r
 -                  \r
 -              mStatusText = mStatusIcon = 0;\r
 -              mStatusCorrect = false;\r
 -              String t_url = ((TextView) findViewById(R.id.host_URL)).getText()\r
 -                      .toString().trim().toLowerCase();\r
 -              \r
 -              switch (result.getCode()) {\r
 -              case OK_SSL:\r
 -                  mIsSslConn = true;\r
 -                  mStatusIcon = android.R.drawable.ic_secure;\r
 -                  mStatusText = R.string.auth_secure_connection;\r
 -                  mStatusCorrect = true;\r
 -                  break;\r
 -                  \r
 -              case OK_NO_SSL:\r
 -              case OK:\r
 -                  mIsSslConn = false;\r
 -                  mStatusCorrect = true;\r
 -                  if (t_url.startsWith("http://") ) {\r
 -                      mStatusText = R.string.auth_connection_established;\r
 -                      mStatusIcon = R.drawable.ic_ok;\r
 -                  } else {\r
 -                      mStatusText = R.string.auth_nossl_plain_ok_title;\r
 -                      mStatusIcon = android.R.drawable.ic_partial_secure;\r
 -                  }\r
 -                  break;\r
 -              \r
 -                  \r
 -              case BAD_OC_VERSION:\r
 -                  mStatusIcon = R.drawable.common_error;\r
 -                  mStatusText = R.string.auth_bad_oc_version_title;\r
 -                  break;\r
 -              case WRONG_CONNECTION:\r
 -                  mStatusIcon = R.drawable.common_error;\r
 -                  mStatusText = R.string.auth_wrong_connection_title;\r
 -                  break;\r
 -              case TIMEOUT:\r
 -                  mStatusIcon = R.drawable.common_error;\r
 -                  mStatusText = R.string.auth_timeout_title;\r
 -                  break;\r
 -              case INCORRECT_ADDRESS:\r
 -                  mStatusIcon = R.drawable.common_error;\r
 -                  mStatusText = R.string.auth_incorrect_address_title;\r
 -                  break;\r
 -                  \r
 -            case SSL_RECOVERABLE_PEER_UNVERIFIED:\r
 -                mStatusIcon = R.drawable.common_error;\r
 -                mStatusText = R.string.auth_ssl_unverified_server_title;\r
 -                mLastSslUntrustedServerResult = result;\r
 -                showDialog(DIALOG_SSL_VALIDATOR); \r
 -                break;\r
 -                  \r
 -            case SSL_ERROR:\r
 -                mStatusIcon = R.drawable.common_error;\r
 -                mStatusText = R.string.auth_ssl_general_error_title;\r
 -                break;\r
 -                \r
 -              case HOST_NOT_AVAILABLE:\r
 -                  mStatusIcon = R.drawable.common_error;\r
 -                  mStatusText = R.string.auth_unknown_host_title;\r
 -                  break;\r
 -              case NO_NETWORK_CONNECTION:\r
 -                  mStatusIcon = R.drawable.no_network;\r
 -                  mStatusText = R.string.auth_no_net_conn_title;\r
 -                  break;\r
 -              case INSTANCE_NOT_CONFIGURED:\r
 -                  mStatusIcon = R.drawable.common_error;\r
 -                  mStatusText = R.string.auth_not_configured_title;\r
 -                  break;\r
 -              case FILE_NOT_FOUND:\r
 -                  mStatusIcon = R.drawable.common_error;\r
 -                  mStatusText = R.string.auth_incorrect_path_title;\r
 -                  break;\r
 -            case UNHANDLED_HTTP_CODE:\r
 -            case UNKNOWN_ERROR:\r
 -                mStatusIcon = R.drawable.common_error;\r
 -                mStatusText = R.string.auth_unknown_error_title;\r
 -                break;\r
 -              default:\r
 -                  Log.e(TAG, "Incorrect connection checker result type: " + result.getHttpCode());\r
 -              }\r
 -              setResultIconAndText(mStatusIcon, mStatusText);\r
 -              if (!mStatusCorrect)\r
 -                  findViewById(R.id.refreshButton).setVisibility(View.VISIBLE);\r
 -              else\r
 -                  findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE);\r
 -              findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);\r
 -              }\r
 -      }\r
 -\r
 -      \r
 +    // If the results of getting the user_code and verification_url are OK, we get the received data and we start\r
 +    // the polling service to oAuth2 server to get a valid token.\r
 +    private void getOAuth2AccessTokenFromJsonResponse() {\r
 +        String deviceCode = null;\r
 +        String verificationUrl = null;\r
 +        String userCode = null;\r
 +        int expiresIn = -1;\r
 +        int interval = -1;\r
 +\r
 +        Log.d(TAG, "ResponseOAuth2->" + mCodeResponseJson.toString());\r
 +\r
 +        try {\r
 +            // We get data that we must show to the user or we will use internally.\r
 +            verificationUrl = mCodeResponseJson.getString(OAuth2GetAuthorizationToken.CODE_VERIFICATION_URL);\r
 +            userCode = mCodeResponseJson.getString(OAuth2GetAuthorizationToken.CODE_USER_CODE);\r
 +            expiresIn = mCodeResponseJson.getInt(OAuth2GetAuthorizationToken.CODE_EXPIRES_IN);                \r
 +\r
 +            // And we get data that we must use to get a token.\r
 +            deviceCode = mCodeResponseJson.getString(OAuth2GetAuthorizationToken.CODE_DEVICE_CODE);\r
 +            interval = mCodeResponseJson.getInt(OAuth2GetAuthorizationToken.CODE_INTERVAL);\r
 +\r
 +        } catch (JSONException e) {\r
 +            Log.e(TAG, "Exception accesing data in Json object" + e.toString());\r
 +        }\r
 +\r
 +        // Updating status widget to OK.\r
 +        updateOAuth2IconAndText(R.drawable.ic_ok, R.string.auth_connection_established);\r
 +        \r
 +        // Showing the dialog with instructions for the user.\r
 +        showDialog(DIALOG_OAUTH2_LOGIN_PROGRESS);\r
 +\r
 +        // Loggin all the data.\r
 +        Log.d(TAG, "verificationUrl->" + verificationUrl);\r
 +        Log.d(TAG, "userCode->" + userCode);\r
 +        Log.d(TAG, "deviceCode->" + deviceCode);\r
 +        Log.d(TAG, "expiresIn->" + expiresIn);\r
 +        Log.d(TAG, "interval->" + interval);\r
 +\r
 +        // Starting the pooling service.\r
 +        try {\r
 +            Intent tokenService = new Intent(this, OAuth2GetTokenService.class);\r
 +            tokenService.putExtra(OAuth2GetTokenService.TOKEN_URI, OAuth2Context.OAUTH2_G_DEVICE_GETTOKEN_URL);\r
 +            tokenService.putExtra(OAuth2GetTokenService.TOKEN_DEVICE_CODE, deviceCode);\r
 +            tokenService.putExtra(OAuth2GetTokenService.TOKEN_INTERVAL, interval);\r
 +\r
 +            startService(tokenService);\r
 +        }\r
 +        catch (Exception e) {\r
 +            Log.e(TAG, "tokenService creation problem :", e);\r
 +        }\r
 +        \r
 +    }   \r
 +    */\r
 +    \r
 +    /* Leave the old OAuth flow\r
 +    // We get data from the oAuth2 token service with this broadcast receiver.\r
 +    private class TokenReceiver extends BroadcastReceiver {\r
 +        /**\r
 +         * The token is received.\r
 +         *  @author\r
 +         * {@link BroadcastReceiver} to enable oAuth2 token receiving.\r
 +         *-/\r
 +        @Override\r
 +        public void onReceive(Context context, Intent intent) {\r
 +            @SuppressWarnings("unchecked")\r
 +            HashMap<String, String> tokenResponse = (HashMap<String, String>)intent.getExtras().get(OAuth2GetTokenService.TOKEN_RECEIVED_DATA);\r
 +            Log.d(TAG, "TokenReceiver->" + tokenResponse.get(OAuth2GetTokenService.TOKEN_ACCESS_TOKEN));\r
 +            dismissDialog(DIALOG_OAUTH2_LOGIN_PROGRESS);\r
 +\r
 +        }\r
 +    }\r
 +    */\r
 +\r
 +    \r
 +    /**\r
 +     * Called from SslValidatorDialog when a new server certificate was correctly saved.\r
 +     */\r
      public void onSavedCertificate() {\r
 -        mAuthThread = mConnChkRunnable.retry(this, mHandler);                \r
 +        mOperationThread = mOcServerChkOperation.retry(this, mHandler);                \r
      }\r
  \r
 +    /**\r
 +     * Called from SslValidatorDialog when a new server certificate could not be saved \r
 +     * when the user requested it.\r
 +     */\r
      @Override\r
      public void onFailedSavingCertificate() {\r
          showDialog(DIALOG_CERT_NOT_SAVED);\r
      }\r
 -    \r
 +\r
  }\r
@@@ -1,9 -1,10 +1,10 @@@
  /* ownCloud Android client application\r
   *   Copyright (C) 2011  Bartek Przybylski\r
+  *   Copyright (C) 2012-2013 ownCloud Inc.\r
   *\r
   *   This program is free software: you can redistribute it and/or modify\r
   *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 3 of the License, or\r
+  *   the Free Software Foundation, either version 2 of the License, or\r
   *   (at your option) any later version.\r
   *\r
   *   This program is distributed in the hope that it will be useful,\r
@@@ -35,6 -36,7 +36,7 @@@ import android.content.Intent
  import android.content.IntentFilter;\r
  import android.content.ServiceConnection;\r
  import android.content.SharedPreferences;\r
+ import android.content.SharedPreferences.Editor;\r
  import android.content.pm.PackageInfo;\r
  import android.content.pm.PackageManager.NameNotFoundException;\r
  import android.content.res.Resources.NotFoundException;\r
@@@ -73,7 -75,7 +75,7 @@@ import com.owncloud.android.files.servi
  import com.owncloud.android.files.services.FileObserverService;\r
  import com.owncloud.android.files.services.FileUploader;\r
  import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;\r
 -import com.owncloud.android.network.OwnCloudClientUtils;\r
 +import com.owncloud.android.operations.CreateFolderOperation;\r
  import com.owncloud.android.operations.OnRemoteOperationListener;\r
  import com.owncloud.android.operations.RemoteOperation;\r
  import com.owncloud.android.operations.RemoteOperationResult;\r
@@@ -82,12 -84,14 +84,13 @@@ import com.owncloud.android.operations.
  import com.owncloud.android.operations.SynchronizeFileOperation;\r
  import com.owncloud.android.operations.RemoteOperationResult.ResultCode;\r
  import com.owncloud.android.syncadapter.FileSyncService;\r
+ import com.owncloud.android.ui.dialog.ChangelogDialog;\r
  import com.owncloud.android.ui.dialog.SslValidatorDialog;\r
  import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;\r
  import com.owncloud.android.ui.fragment.FileDetailFragment;\r
  import com.owncloud.android.ui.fragment.OCFileListFragment;\r
  \r
  import com.owncloud.android.R;\r
 -import eu.alefzero.webdav.WebdavClient;\r
  \r
  /**\r
   * Displays, what files the user has available in his ownCloud.\r
@@@ -115,7 -119,6 +118,7 @@@ public class FileDisplayActivity extend
      private OCFileListFragment mFileList;\r
      \r
      private boolean mDualPane;\r
 +    private Handler mHandler;\r
      \r
      private static final int DIALOG_SETUP_ACCOUNT = 0;\r
      private static final int DIALOG_CREATE_DIR = 1;\r
      private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 4;\r
      private static final int DIALOG_SSL_VALIDATOR = 5;\r
      private static final int DIALOG_CERT_NOT_SAVED = 6;\r
+     private static final String DIALOG_CHANGELOG_TAG = "DIALOG_CHANGELOG";\r
  \r
      \r
      private static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;\r
      public void onCreate(Bundle savedInstanceState) {\r
          Log.d(getClass().toString(), "onCreate() start");\r
          super.onCreate(savedInstanceState);\r
 +        \r
 +        mHandler = new Handler();\r
  \r
          /// Load of parameters from received intent\r
-         mCurrentDir = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); // no check necessary, mCurrenDir == null if the parameter is not in the intent\r
          Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);\r
-         if (account != null)\r
-             AccountUtils.setCurrentOwnCloudAccount(this, account.name);\r
+         if (account != null && AccountUtils.setCurrentOwnCloudAccount(this, account.name)) {\r
+             mCurrentDir = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); \r
+         }\r
          \r
          /// Load of saved instance state: keep this always before initDataFromCurrentAccount()\r
          if(savedInstanceState != null) {\r
          // Drop-down navigation \r
          mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);\r
          OCFile currFile = mCurrentDir;\r
-         while(currFile != null && currFile.getFileName() != OCFile.PATH_SEPARATOR) {\r
+         while(mStorageManager != null && currFile != null && currFile.getFileName() != OCFile.PATH_SEPARATOR) {\r
              mDirectories.add(currFile.getFileName());\r
              currFile = mStorageManager.getFileById(currFile.getParentId());\r
          }\r
          actionBar.setListNavigationCallbacks(mDirectories, this);\r
          setSupportProgressBarIndeterminateVisibility(false);        // always AFTER setContentView(...) ; to workaround bug in its implementation\r
          \r
+         \r
+         // show changelog, if needed\r
+         //showChangeLog();\r
+         \r
          Log.d(getClass().toString(), "onCreate() end");\r
      }\r
  \r
      \r
      /**\r
+      * Shows a dialog with the change log of the current version after each app update\r
+      * \r
+      *  TODO make it permanent; by now, only to advice the workaround app for 4.1.x\r
+      */\r
+     private void showChangeLog() {\r
+         if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.JELLY_BEAN) {\r
+             final String KEY_VERSION = "version";\r
+             SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());\r
+             int currentVersionNumber = 0;\r
+             int savedVersionNumber = sharedPref.getInt(KEY_VERSION, 0);\r
+             try {\r
+                 PackageInfo pi          = getPackageManager().getPackageInfo(getPackageName(), 0);\r
+                 currentVersionNumber    = pi.versionCode;\r
+             } catch (Exception e) {}\r
+      \r
+             if (currentVersionNumber > savedVersionNumber) {\r
+                 ChangelogDialog.newInstance(true).show(getSupportFragmentManager(), DIALOG_CHANGELOG_TAG);\r
+                 Editor editor   = sharedPref.edit();\r
+                 editor.putInt(KEY_VERSION, currentVersionNumber);\r
+                 editor.commit();\r
+             }\r
+         }\r
+     }\r
+     \r
\r
+     /**\r
       * Launches the account creation activity. To use when no ownCloud account is available\r
       */\r
      private void createFirstAccount() {\r
          Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);\r
 -        intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
 +        intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTHORITY });\r
          startActivity(intent);  // the new activity won't be created until this.onStart() and this.onResume() are finished;\r
      }\r
  \r
      }\r
  \r
      private void startSynchronization() {\r
 -        ContentResolver.cancelSync(null, AccountAuthenticator.AUTH_TOKEN_TYPE);   // cancel the current synchronizations of any ownCloud account\r
 +        ContentResolver.cancelSync(null, AccountAuthenticator.AUTHORITY);   // cancel the current synchronizations of any ownCloud account\r
          Bundle bundle = new Bundle();\r
          bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);\r
          ContentResolver.requestSync(\r
                  AccountUtils.getCurrentOwnCloudAccount(this),\r
 -                AccountAuthenticator.AUTH_TOKEN_TYPE, bundle);\r
 +                AccountAuthenticator.AUTHORITY, bundle);\r
      }\r
  \r
  \r
                              \r
                              // Create directory\r
                              path += directoryName + OCFile.PATH_SEPARATOR;\r
 -                            Thread thread = new Thread(new DirectoryCreator(path,  AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), new Handler()));\r
 -                            thread.start();\r
 +                            RemoteOperation operation = new CreateFolderOperation(path, mCurrentDir.getFileId(), mStorageManager);\r
 +                            operation.execute(  AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), \r
 +                                                FileDisplayActivity.this, \r
 +                                                FileDisplayActivity.this, \r
 +                                                mHandler,\r
 +                                                FileDisplayActivity.this);\r
                              \r
                              dialog.dismiss();\r
                              \r
          return !mDirectories.isEmpty();\r
      }\r
  \r
 -    private class DirectoryCreator implements Runnable {\r
 -        private String mTargetPath;\r
 -        private Account mAccount;\r
 -        private Handler mHandler; \r
 -    \r
 -        public DirectoryCreator(String targetPath, Account account, Handler handler) {\r
 -            mTargetPath = targetPath;\r
 -            mAccount = account;\r
 -            mHandler = handler;\r
 -        }\r
 -    \r
 -        @Override\r
 -        public void run() {\r
 -            WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext());\r
 -            boolean created = wdc.createDirectory(mTargetPath);\r
 -            if (created) {\r
 -                mHandler.post(new Runnable() {\r
 -                    @Override\r
 -                    public void run() { \r
 -                        dismissDialog(DIALOG_SHORT_WAIT);\r
 -                        \r
 -                        // Save new directory in local database\r
 -                        OCFile newDir = new OCFile(mTargetPath);\r
 -                        newDir.setMimetype("DIR");\r
 -                        newDir.setParentId(mCurrentDir.getFileId());\r
 -                        mStorageManager.saveFile(newDir);\r
 -    \r
 -                        // Display the new folder right away\r
 -                        mFileList.listDirectory();\r
 -                    }\r
 -                });\r
 -                \r
 -            } else {\r
 -                mHandler.post(new Runnable() {\r
 -                    @Override\r
 -                    public void run() {\r
 -                        dismissDialog(DIALOG_SHORT_WAIT);\r
 -                        try {\r
 -                            Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); \r
 -                            msg.show();\r
 -                        \r
 -                        } catch (NotFoundException e) {\r
 -                            Log.e(TAG, "Error while trying to show fail message " , e);\r
 -                        }\r
 -                    }\r
 -                });\r
 -            }\r
 -        }\r
 -    \r
 -    }\r
  \r
      // Custom array adapter to override text colors\r
      private class CustomArrayAdapter<T> extends ArrayAdapter<T> {\r
              \r
          } else if (operation instanceof SynchronizeFileOperation) {\r
              onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);\r
 +            \r
 +        } else if (operation instanceof CreateFolderOperation) {\r
 +            onCreateFolderOperationFinish((CreateFolderOperation)operation, result);\r
 +        }\r
 +    }\r
 +\r
 +    /**\r
 +     * Updates the view associated to the activity after the finish of an operation trying create a new folder\r
 +     * \r
 +     * @param operation     Creation operation performed.\r
 +     * @param result        Result of the creation.\r
 +     */\r
 +    private void onCreateFolderOperationFinish(CreateFolderOperation operation, RemoteOperationResult result) {\r
 +        if (result.isSuccess()) {\r
 +            dismissDialog(DIALOG_SHORT_WAIT);\r
 +            mFileList.listDirectory();\r
 +            \r
 +        } else {\r
 +            dismissDialog(DIALOG_SHORT_WAIT);\r
 +            try {\r
 +                Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); \r
 +                msg.show();\r
 +                    \r
 +            } catch (NotFoundException e) {\r
 +                Log.e(TAG, "Error while trying to show fail message " , e);\r
 +            }\r
          }\r
      }\r
  \r
@@@ -3,7 -3,7 +3,7 @@@
   *\r
   *   This program is free software: you can redistribute it and/or modify\r
   *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 3 of the License, or\r
+  *   the Free Software Foundation, either version 2 of the License, or\r
   *   (at your option) any later version.\r
   *\r
   *   This program is distributed in the hope that it will be useful,\r
@@@ -113,9 -113,9 +113,9 @@@ public class LandingActivity extends Sh
          dialog.dismiss();\r
          switch (which) {\r
          case DialogInterface.BUTTON_POSITIVE:\r
 -            Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");\r
 +            Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);\r
              intent.putExtra("authorities",\r
 -                    new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
 +                    new String[] { AccountAuthenticator.AUTHORITY });\r
              startActivity(intent);\r
              break;\r
          case DialogInterface.BUTTON_NEGATIVE:\r
@@@ -1,9 -1,10 +1,10 @@@
  /* ownCloud Android client application\r
   *   Copyright (C) 2011  Bartek Przybylski\r
+  *   Copyright (C) 2012-2013 ownCloud Inc.\r
   *\r
   *   This program is free software: you can redistribute it and/or modify\r
   *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 3 of the License, or\r
+  *   the Free Software Foundation, either version 2 of the License, or\r
   *   (at your option) any later version.\r
   *\r
   *   This program is distributed in the hope that it will be useful,\r
  package com.owncloud.android.ui.fragment;\r
  \r
  import java.io.File;\r
 -import java.util.ArrayList;\r
 -import java.util.List;\r
 -\r
 -import org.apache.commons.httpclient.methods.GetMethod;\r
 -import org.apache.commons.httpclient.methods.PostMethod;\r
 -import org.apache.commons.httpclient.methods.StringRequestEntity;\r
 -import org.apache.commons.httpclient.params.HttpConnectionManagerParams;\r
 -import org.apache.http.HttpStatus;\r
 -import org.apache.http.NameValuePair;\r
 -import org.apache.http.client.utils.URLEncodedUtils;\r
 -import org.apache.http.message.BasicNameValuePair;\r
 -import org.apache.http.protocol.HTTP;\r
 -import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;\r
 -import org.json.JSONObject;\r
 +\r
 +import org.apache.commons.httpclient.Credentials;\r
  \r
  import android.accounts.Account;\r
  import android.accounts.AccountManager;\r
@@@ -54,6 -67,7 +55,6 @@@ import android.widget.TextView
  import android.widget.Toast;\r
  \r
  import com.actionbarsherlock.app.SherlockFragment;\r
 -import com.owncloud.android.AccountUtils;\r
  import com.owncloud.android.DisplayUtils;\r
  import com.owncloud.android.authenticator.AccountAuthenticator;\r
  import com.owncloud.android.datamodel.FileDataStorageManager;\r
@@@ -63,7 -77,7 +64,7 @@@ import com.owncloud.android.files.servi
  import com.owncloud.android.files.services.FileUploader;\r
  import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;\r
  import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;\r
 -import com.owncloud.android.network.OwnCloudClientUtils;\r
 +import com.owncloud.android.network.BearerCredentials;\r
  import com.owncloud.android.operations.OnRemoteOperationListener;\r
  import com.owncloud.android.operations.RemoteOperation;\r
  import com.owncloud.android.operations.RemoteOperationResult;\r
@@@ -77,8 -91,10 +78,8 @@@ import com.owncloud.android.ui.activity
  import com.owncloud.android.ui.activity.TransferServiceGetter;\r
  import com.owncloud.android.ui.dialog.EditNameDialog;\r
  import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;\r
 -import com.owncloud.android.utils.OwnCloudVersion;\r
  \r
  import com.owncloud.android.R;\r
 -import eu.alefzero.webdav.WebdavClient;\r
  import eu.alefzero.webdav.WebdavUtils;\r
  \r
  /**\r
@@@ -293,7 -309,8 +294,7 @@@ public class FileDetailFragment extend
                      \r
                  } else {\r
                      mLastRemoteOperation = new SynchronizeFileOperation(mFile, null, mStorageManager, mAccount, true, false, getActivity());\r
 -                    WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());\r
 -                    mLastRemoteOperation.execute(wc, this, mHandler);\r
 +                    mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());\r
                  \r
                      // update ui \r
                      boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
                  mLastRemoteOperation = new RemoveFileOperation( mFile, \r
                                                                  true, \r
                                                                  mStorageManager);\r
 -                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());\r
 -                mLastRemoteOperation.execute(wc, this, mHandler);\r
 -                \r
 +                mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());\r
                  boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
                  getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
              }\r
              \r
              // set file details\r
              setFilename(mFile.getFileName());\r
-             setFiletype(DisplayUtils.convertMIMEtoPrettyPrint(mFile\r
-                     .getMimetype()));\r
+             setFiletype(mFile.getMimetype());\r
              setFilesize(mFile.getFileLength());\r
              if(ocVersionSupportsTimeCreated()){\r
                  setTimeCreated(mFile.getCreationTimestamp());\r
       */\r
      private void setFiletype(String mimetype) {\r
          TextView tv = (TextView) getView().findViewById(R.id.fdType);\r
-         if (tv != null)\r
-             tv.setText(mimetype);\r
+         if (tv != null) {\r
+             String printableMimetype = DisplayUtils.convertMIMEtoPrettyPrint(mimetype);;        \r
+             tv.setText(printableMimetype);\r
+         }\r
+         ImageView iv = (ImageView) getView().findViewById(R.id.fdIcon);\r
+         if (iv != null) {\r
+             iv.setImageResource(DisplayUtils.getResourceId(mimetype));\r
+         }\r
      }\r
  \r
      /**\r
                  if (mFile.getRemotePath().equals(uploadRemotePath) ||\r
                      renamedInUpload) {\r
                      if (uploadWasFine) {\r
 -                        mFile = mStorageManager.getFileByPath(uploadRemotePath);\r
 +                       mFile = mStorageManager.getFileByPath(uploadRemotePath);\r
                      }\r
                      if (renamedInUpload) {\r
                          String newName = (new File(uploadRemotePath)).getName();\r
      \r
  \r
      // this is a temporary class for sharing purposes, it need to be replaced in transfer service\r
 +    /*\r
      @SuppressWarnings("unused")\r
      private class ShareRunnable implements Runnable {\r
          private String mPath;\r
              }\r
          }\r
      }\r
 +    */\r
      \r
      public void onDismiss(EditNameDialog dialog) {\r
          if (dialog.getResult()) {\r
                                                              mAccount, \r
                                                              newFilename, \r
                                                              new FileDataStorageManager(mAccount, getActivity().getContentResolver()));\r
 -            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());\r
 -            mLastRemoteOperation.execute(wc, this, mHandler);\r
 +            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());\r
              boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
              getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
          }\r
       */\r
      @Override\r
      public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {\r
 -        if (operation.equals(mLastRemoteOperation)) {\r
 -            if (operation instanceof RemoveFileOperation) {\r
 -                onRemoveFileOperationFinish((RemoveFileOperation)operation, result);\r
 +        if (operation instanceof RemoveFileOperation) {\r
 +            onRemoveFileOperationFinish((RemoveFileOperation)operation, result);\r
                  \r
 -            } else if (operation instanceof RenameFileOperation) {\r
 -                onRenameFileOperationFinish((RenameFileOperation)operation, result);\r
 +        } else if (operation instanceof RenameFileOperation) {\r
 +            onRenameFileOperationFinish((RenameFileOperation)operation, result);\r
                  \r
 -            } else if (operation instanceof SynchronizeFileOperation) {\r
 -                onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);\r
 -            }\r
 +        } else if (operation instanceof SynchronizeFileOperation) {\r
 +            onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);\r
          }\r
      }\r
      \r
@@@ -1,9 -1,10 +1,10 @@@
  /* ownCloud Android client application
   *   Copyright (C) 2011  Bartek Przybylski
+  *   Copyright (C) 2012-2013 ownCloud Inc.
   *
   *   This program is free software: you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
-  *   the Free Software Foundation, either version 3 of the License, or
+  *   the Free Software Foundation, either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
@@@ -27,6 -28,7 +28,6 @@@ import com.owncloud.android.datamodel.D
  import com.owncloud.android.datamodel.OCFile;
  import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
  import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
 -import com.owncloud.android.network.OwnCloudClientUtils;
  import com.owncloud.android.operations.OnRemoteOperationListener;
  import com.owncloud.android.operations.RemoteOperation;
  import com.owncloud.android.operations.RemoveFileOperation;
@@@ -40,6 -42,7 +41,6 @@@ import com.owncloud.android.ui.dialog.E
  import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
  import com.owncloud.android.ui.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
  
 -import eu.alefzero.webdav.WebdavClient;
  import eu.alefzero.webdav.WebdavUtils;
  
  import android.accounts.Account;
@@@ -314,7 -317,8 +315,7 @@@ public class OCFileListFragment extend
              case R.id.download_file_item: {
                  Account account = AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity());
                  RemoteOperation operation = new SynchronizeFileOperation(mTargetFile, null, mContainerActivity.getStorageManager(), account, true, false, getSherlockActivity());
 -                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(account, getSherlockActivity().getApplicationContext());
 -                operation.execute(wc, mContainerActivity, mHandler);
 +                operation.execute(account, getSherlockActivity(), mContainerActivity, mHandler, getSherlockActivity());
                  getSherlockActivity().showDialog(FileDisplayActivity.DIALOG_SHORT_WAIT);
                  return true;
              }
                                                                  AccountUtils.getCurrentOwnCloudAccount(getActivity()), 
                                                                  newFilename, 
                                                                  mContainerActivity.getStorageManager());
 -            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity().getApplicationContext());
 -            operation.execute(wc, mContainerActivity, mHandler);
 +            operation.execute(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity(), mContainerActivity, mHandler, getSherlockActivity());
              getActivity().showDialog(FileDisplayActivity.DIALOG_SHORT_WAIT);
          }
      }
                  RemoteOperation operation = new RemoveFileOperation( mTargetFile, 
                                                                      true, 
                                                                      mContainerActivity.getStorageManager());
 -                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity().getApplicationContext());
 -                operation.execute(wc, mContainerActivity, mHandler);
 +                operation.execute(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity(), mContainerActivity, mHandler, getSherlockActivity());
                  
                  getActivity().showDialog(FileDisplayActivity.DIALOG_SHORT_WAIT);
              }
@@@ -1,9 -1,10 +1,10 @@@
  /* ownCloud Android client application\r
   *   Copyright (C) 2011  Bartek Przybylski\r
+  *   Copyright (C) 2012-2013 ownCloud Inc.\r
   *\r
   *   This program is free software: you can redistribute it and/or modify\r
   *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 3 of the License, or\r
+  *   the Free Software Foundation, either version 2 of the License, or\r
   *   (at your option) any later version.\r
   *\r
   *   This program is distributed in the hope that it will be useful,\r
@@@ -22,20 -23,14 +23,20 @@@ import java.io.File
  import java.io.FileOutputStream;\r
  import java.io.IOException;\r
  import java.io.InputStream;\r
 +import java.util.ArrayList;\r
 +import java.util.List;\r
  \r
  import org.apache.commons.httpclient.Credentials;\r
 +import org.apache.commons.httpclient.HostConfiguration;\r
  import org.apache.commons.httpclient.HttpClient;\r
  import org.apache.commons.httpclient.HttpConnectionManager;\r
  import org.apache.commons.httpclient.HttpException;\r
 +import org.apache.commons.httpclient.HttpMethod;\r
  import org.apache.commons.httpclient.HttpMethodBase;\r
 +import org.apache.commons.httpclient.HttpState;\r
  import org.apache.commons.httpclient.HttpVersion;\r
  import org.apache.commons.httpclient.UsernamePasswordCredentials;\r
 +import org.apache.commons.httpclient.auth.AuthPolicy;\r
  import org.apache.commons.httpclient.auth.AuthScope;\r
  import org.apache.commons.httpclient.methods.GetMethod;\r
  import org.apache.commons.httpclient.methods.HeadMethod;\r
@@@ -45,9 -40,7 +46,9 @@@ import org.apache.http.HttpStatus
  import org.apache.http.params.CoreProtocolPNames;\r
  import org.apache.jackrabbit.webdav.client.methods.DavMethod;\r
  import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;\r
 -import org.apache.jackrabbit.webdav.client.methods.MkColMethod;\r
 +\r
 +import com.owncloud.android.network.BearerAuthScheme;\r
 +import com.owncloud.android.network.BearerCredentials;\r
  \r
  import android.net.Uri;\r
  import android.util.Log;\r
@@@ -71,28 -64,18 +72,28 @@@ public class WebdavClient extends HttpC
          getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);\r
      }\r
  \r
 -    public void setCredentials(String username, String password) {\r
 -        getParams().setAuthenticationPreemptive(true);\r
 -        getState().setCredentials(AuthScope.ANY,\r
 -                getCredentials(username, password));\r
 +    public void setBearerCredentials(String accessToken) {\r
 +        AuthPolicy.registerAuthScheme(BearerAuthScheme.AUTH_POLICY, BearerAuthScheme.class);\r
 +        \r
 +        List<String> authPrefs = new ArrayList<String>(1);\r
 +        authPrefs.add(BearerAuthScheme.AUTH_POLICY);\r
 +        getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);        \r
 +        \r
 +        mCredentials = new BearerCredentials(accessToken);\r
 +        getState().setCredentials(AuthScope.ANY, mCredentials);\r
      }\r
  \r
 -    private Credentials getCredentials(String username, String password) {\r
 -        if (mCredentials == null)\r
 -            mCredentials = new UsernamePasswordCredentials(username, password);\r
 -        return mCredentials;\r
 +    public void setBasicCredentials(String username, String password) {\r
 +        List<String> authPrefs = new ArrayList<String>(1);\r
 +        authPrefs.add(AuthPolicy.BASIC);\r
 +        getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);        \r
 +        \r
 +        getParams().setAuthenticationPreemptive(true);\r
 +        mCredentials = new UsernamePasswordCredentials(username, password);\r
 +        getState().setCredentials(AuthScope.ANY, mCredentials);\r
      }\r
      \r
 +    \r
      /**\r
       * Downloads a file in remoteFilepath to the local targetPath.\r
       * \r
          return status;\r
      }\r
  \r
 -    /**\r
 -     * Creates a remote directory with the received path.\r
 -     * \r
 -     * @param path      Path of the directory to create, URL DECODED\r
 -     * @return          'True' when the directory is successfully created\r
 -     */\r
 -    public boolean createDirectory(String path) {\r
 -        boolean result = false;\r
 -        int status = -1;\r
 -        MkColMethod mkcol = new MkColMethod(mUri.toString() + WebdavUtils.encodePath(path));\r
 -        try {\r
 -            Log.d(TAG, "Creating directory " + path);\r
 -            status = executeMethod(mkcol);\r
 -            Log.d(TAG, "Status returned: " + status);\r
 -            result = mkcol.succeeded();\r
 -            \r
 -            Log.d(TAG, "MKCOL to " + path + " finished with HTTP status " + status + (!result?"(FAIL)":""));\r
 -            exhaustResponse(mkcol.getResponseBodyAsStream());\r
 -            \r
 -        } catch (Exception e) {\r
 -            logException(e, "creating directory " + path);\r
 -            \r
 -        } finally {\r
 -            mkcol.releaseConnection();    // let the connection available for other methods\r
 -        }\r
 -        return result;\r
 -    }\r
 -    \r
      \r
      /**\r
       * Check if a file exists in the OC server\r
      public Uri getBaseUri() {\r
          return mUri;\r
      }\r
 +    \r
 +\r
 +    @Override\r
 +    public int executeMethod(HostConfiguration hostconfig, final HttpMethod method, final HttpState state) throws IOException, HttpException  {\r
 +        if (mCredentials instanceof BearerCredentials) {\r
 +            method.getHostAuthState().setAuthScheme(AuthPolicy.getAuthScheme(BearerAuthScheme.AUTH_POLICY));\r
 +            method.getHostAuthState().setAuthAttempted(true);\r
 +        }\r
 +        return super.executeMethod(hostconfig, method, state);\r
 +    }\r
 +\r
 +    \r
 +    public final Credentials getCredentials() {\r
 +        return mCredentials;\r
 +    }\r
  \r
  }\r