Browse Source

Merge pull request #152 from owncloud/oauth_login

Oauth login and authenticator refactoring
David A. Velasco 12 years ago
parent
commit
52bd01bced
74 changed files with 3309 additions and 2151 deletions
  1. 26 18
      AndroidManifest.xml
  2. 238 186
      res/layout-land/account_setup.xml
  3. 253 189
      res/layout/account_setup.xml
  4. 23 0
      res/values/oauth2_configuration.xml
  5. 17 3
      res/values/strings.xml
  6. 4 0
      res/values/styles.xml
  7. 8 3
      src/com/owncloud/android/AccountUtils.java
  8. 0 2
      src/com/owncloud/android/DisplayUtils.java
  9. 6 7
      src/com/owncloud/android/Uploader.java
  10. 144 111
      src/com/owncloud/android/authentication/AccountAuthenticator.java
  11. 1 1
      src/com/owncloud/android/authentication/AccountAuthenticatorService.java
  12. 1085 0
      src/com/owncloud/android/authentication/AuthenticatorActivity.java
  13. 53 0
      src/com/owncloud/android/authentication/OAuth2Constants.java
  14. 0 88
      src/com/owncloud/android/authenticator/AuthenticationRunnable.java
  15. 0 25
      src/com/owncloud/android/authenticator/OnAuthenticationResultListener.java
  16. 0 29
      src/com/owncloud/android/authenticator/OnConnectCheckListener.java
  17. 0 1
      src/com/owncloud/android/datamodel/FileDataStorageManager.java
  18. 0 1
      src/com/owncloud/android/db/DbHandler.java
  19. 0 1
      src/com/owncloud/android/extensions/ExtensionsAvailableDialog.java
  20. 0 1
      src/com/owncloud/android/extensions/ExtensionsListActivity.java
  21. 0 1
      src/com/owncloud/android/files/BootupBroadcastReceiver.java
  22. 5 4
      src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java
  23. 1 5
      src/com/owncloud/android/files/OwnCloudFileObserver.java
  24. 51 25
      src/com/owncloud/android/files/services/FileDownloader.java
  25. 0 1
      src/com/owncloud/android/files/services/FileObserverService.java
  26. 0 55
      src/com/owncloud/android/files/services/FileOperation.java
  27. 67 35
      src/com/owncloud/android/files/services/FileUploader.java
  28. 0 1
      src/com/owncloud/android/location/LocationServiceLauncherReciever.java
  29. 0 1
      src/com/owncloud/android/location/LocationUpdateService.java
  30. 0 2
      src/com/owncloud/android/network/AdvancedSslSocketFactory.java
  31. 0 2
      src/com/owncloud/android/network/AdvancedX509TrustManager.java
  32. 268 0
      src/com/owncloud/android/network/BearerAuthScheme.java
  33. 97 0
      src/com/owncloud/android/network/BearerCredentials.java
  34. 52 31
      src/com/owncloud/android/network/OwnCloudClientUtils.java
  35. 0 1
      src/com/owncloud/android/operations/ChunkedUploadFileOperation.java
  36. 94 0
      src/com/owncloud/android/operations/CreateFolderOperation.java
  37. 0 1
      src/com/owncloud/android/operations/DownloadFileOperation.java
  38. 94 0
      src/com/owncloud/android/operations/ExistenceCheckOperation.java
  39. 174 0
      src/com/owncloud/android/operations/OAuth2GetAccessToken.java
  40. 3 4
      src/com/owncloud/android/operations/OwnCloudServerCheckOperation.java
  41. 152 5
      src/com/owncloud/android/operations/RemoteOperation.java
  42. 30 5
      src/com/owncloud/android/operations/RemoteOperationResult.java
  43. 0 2
      src/com/owncloud/android/operations/RemoveFileOperation.java
  44. 1 2
      src/com/owncloud/android/operations/RenameFileOperation.java
  45. 0 1
      src/com/owncloud/android/operations/SynchronizeFileOperation.java
  46. 0 1
      src/com/owncloud/android/operations/SynchronizeFolderOperation.java
  47. 1 2
      src/com/owncloud/android/operations/UpdateOCVersionOperation.java
  48. 0 1
      src/com/owncloud/android/providers/FileContentProvider.java
  49. 1 1
      src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java
  50. 1 1
      src/com/owncloud/android/syncadapter/ContactSyncAdapter.java
  51. 31 12
      src/com/owncloud/android/syncadapter/FileSyncAdapter.java
  52. 4 5
      src/com/owncloud/android/ui/activity/AccountSelectActivity.java
  53. 0 609
      src/com/owncloud/android/ui/activity/AuthenticatorActivity.java
  54. 0 1
      src/com/owncloud/android/ui/activity/ErrorsWhileCopyingHandlerActivity.java
  55. 17 11
      src/com/owncloud/android/ui/activity/FailedUploadActivity.java
  56. 0 1
      src/com/owncloud/android/ui/activity/FileDetailActivity.java
  57. 47 151
      src/com/owncloud/android/ui/activity/FileDisplayActivity.java
  58. 3 14
      src/com/owncloud/android/ui/activity/InstantUploadActivity.java
  59. 3 3
      src/com/owncloud/android/ui/activity/LandingActivity.java
  60. 0 1
      src/com/owncloud/android/ui/activity/UploadFilesActivity.java
  61. 0 1
      src/com/owncloud/android/ui/dialog/SslValidatorDialog.java
  62. 0 1
      src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java
  63. 170 224
      src/com/owncloud/android/ui/fragment/FileDetailFragment.java
  64. 0 1
      src/com/owncloud/android/ui/fragment/LocalFileListFragment.java
  65. 3 9
      src/com/owncloud/android/ui/fragment/OCFileListFragment.java
  66. 4 4
      src/com/owncloud/android/ui/preview/FileDownloadFragment.java
  67. 7 10
      src/com/owncloud/android/ui/preview/PreviewImageActivity.java
  68. 11 14
      src/com/owncloud/android/ui/preview/PreviewImageFragment.java
  69. 0 8
      src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java
  70. 15 18
      src/com/owncloud/android/ui/preview/PreviewMediaFragment.java
  71. 11 11
      src/com/owncloud/android/ui/preview/PreviewVideoActivity.java
  72. 0 1
      src/com/owncloud/android/utils/FileStorageUtils.java
  73. 33 184
      src/eu/alefzero/webdav/WebdavClient.java
  74. 0 1
      src/eu/alefzero/webdav/WebdavEntry.java

+ 26 - 18
AndroidManifest.xml

@@ -90,7 +90,7 @@
         <activity android:name=".ui.activity.PreferencesNewSessionewSession" >
         </activity>
         
-		<activity	android:name="com.owncloud.android.ui.preview.PreviewImageActivity" />
+        <activity	android:name="com.owncloud.android.ui.preview.PreviewImageActivity" />
 		        
         <activity	android:name="com.owncloud.android.ui.preview.PreviewVideoActivity"
 					android:label="@string/app_name"
@@ -98,7 +98,7 @@
 		</activity>        
 
         <service
-            android:name=".authenticator.AccountAuthenticatorService"
+            android:name=".authentication.AccountAuthenticatorService"
             android:exported="true">
             <intent-filter  android:priority="100">
                 <action android:name="android.accounts.AccountAuthenticator" />
@@ -130,9 +130,16 @@
         </provider>
 
         <activity
-            android:name=".ui.activity.AuthenticatorActivity"
+            android:name=".authentication.AuthenticatorActivity"
             android:exported="true"
-            android:theme="@style/Theme.ownCloud.noActionBar" >
+            android:theme="@style/Theme.ownCloud.noActionBar" 
+            android:launchMode="singleTask">
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <data android:scheme="@string/oauth2_redirect_scheme" />
+            </intent-filter>
             <intent-filter>
                 <action android:name="com.owncloud.android.workaround.accounts.CREATE" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -154,21 +161,22 @@
         
         <activity android:name=".ui.activity.LogHistoryActivity"/>
         
-        <receiver android:name=".files.InstantUploadBroadcastReceiver">
-            <intent-filter>
-                <action android:name="com.android.camera.NEW_PICTURE" />
-                <data android:mimeType="image/*" />
+        <receiver android:name=".files.InstantUploadBroadcastReceiver">
+            <intent-filter>
+                <action android:name="com.android.camera.NEW_PICTURE" />
+                <data android:mimeType="image/*" />
             </intent-filter>
             <intent-filter>
                 <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
-            </intent-filter>
-        </receiver>
-        <receiver android:name=".files.BootupBroadcastReceiver">
-            <intent-filter>
-                <action android:name="android.intent.action.BOOT_COMPLETED"/>
-            </intent-filter>
-        </receiver>
-        <service android:name=".files.services.FileObserverService"/>
-    </application>
-    
+            </intent-filter>
+        </receiver>
+        <receiver android:name=".files.BootupBroadcastReceiver">
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED"/>
+            </intent-filter>
+        </receiver>
+        <service android:name=".files.services.FileObserverService"/>
+        
+    </application>
+
 </manifest>

+ 238 - 186
res/layout-land/account_setup.xml

@@ -1,186 +1,238 @@
-<?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 version 2,
-  as published by the Free Software Foundation.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program.  If not, see <http://www.gnu.org/licenses/>.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:oc="http://schemas.android.com/apk/res/com.owncloud.android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:focusable="true"
-    android:gravity="center|fill"
-    android:orientation="vertical" >
-
-    <FrameLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:layout_marginLeft="16dip"
-        android:layout_marginRight="16dip"
-        android:layout_weight="1" >
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent" >
-
-            <ImageView
-                android:id="@+id/imageView1"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_margin="7dp"
-                android:layout_weight="1"
-                android:src="@drawable/owncloud_logo" />
-
-            <LinearLayout
-                android:id="@+id/LinearLayout1"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:layout_weight="1"
-                android:orientation="vertical" >
-
-                <FrameLayout
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="1" >
-
-                    <EditText
-                        android:id="@+id/host_URL"
-                        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">
-                        <requestFocus />
-                    </EditText>
-
-                    <ImageView
-                        android:id="@+id/refreshButton"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_gravity="right|center_vertical"
-                        android:src="@drawable/ic_action_refresh_black"
-                        android:visibility="invisible" />
-                </FrameLayout>
-
-                <LinearLayout
-                    android:layout_width="match_parent"
-                    android:layout_height="50dp"
-                    android:layout_weight="1" >
-
-                    <ImageView
-                        android:id="@+id/action_indicator"
-                        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"
-                        android:visibility="invisible" />
-
-                    <TextView
-                        android:id="@+id/status_text"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:text="TextView"
-                        android:visibility="invisible" />
-                </LinearLayout>
-
-                <TextView
-                    android:id="@+id/textView2"
-                    android:layout_width="wrap_content"
-                    android:layout_height="0dp"
-                    android:layout_weight="1"
-                    android:text="@string/auth_login_details"
-                    android:textAppearance="?android:attr/textAppearanceSmall" />
-
-                <EditText
-                    android:id="@+id/account_username"
-                    android:layout_width="match_parent"
-                    android:layout_height="0dp"
-                    android:layout_weight="1"
-                    android:ems="10"
-                    android:hint="@string/auth_username"
-                    android:inputType="textNoSuggestions" />
-
-                <FrameLayout
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="1" >
-
-                    <EditText
-                        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:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_gravity="right|center_vertical"
-                        android:src="@android:drawable/ic_menu_view"
-                        android:visibility="invisible" />
-                </FrameLayout>
-            </LinearLayout>
-        </LinearLayout>
-    </FrameLayout>
-
-    <RelativeLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true" >
-
-        <LinearLayout
-            android:id="@+id/buttons_layout"        
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:weightSum="1">
-
-            <Button
-                android:id="@+id/buttonOK"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_weight=".5"
-                android:layout_marginLeft="16dip"
-		        android:layout_marginRight="16dip"
-                android:enabled="false"
-                android:onClick="onOkClick"
-                android:text="@string/setup_btn_connect"
-                android:textColor="@android:color/black" />
-            
-        </LinearLayout>
-        
-		<Button
-			android:id="@+id/account_register"
-			android:layout_width="wrap_content"
-			android:layout_height="wrap_content"
-			android:layout_below="@id/buttons_layout"
-			android:layout_centerHorizontal="true"
-			android:onClick="onRegisterClick"
-			android:paddingTop="10dp"
-			android:paddingBottom="10dp"
-			android:textColor="#0000FF"
-			android:background="@android:color/transparent" />
-			<!-- android:text="@string/app_name @string/auth_register" /-->
-        
-    </RelativeLayout>
-
-</LinearLayout>
+<?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 version 2,
+  as published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:oc="http://schemas.android.com/apk/res/com.owncloud.android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:focusable="true"
+    android:gravity="center|fill"
+    android:orientation="vertical" >
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginLeft="16dip"
+        android:layout_marginRight="16dip"
+        android:layout_weight="1" >
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" >
+
+            <ImageView
+                android:id="@+id/imageView1"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_margin="7dp"
+                android:layout_weight="1"
+                android:src="@drawable/owncloud_logo" />
+
+            <LinearLayout
+                android:id="@+id/LinearLayout1"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:layout_weight="1"
+                android:orientation="vertical" >
+
+                <FrameLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1" >
+
+                    <EditText
+                        android:id="@+id/hostUrlInput"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:ems="10"
+                        android:hint="@string/auth_host_url"
+                        android:inputType="textNoSuggestions">
+                        <requestFocus />
+                    </EditText>
+
+                    <ImageView
+                        android:id="@+id/refreshButton"
+                        android:layout_width="wrap_content"
+                        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>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="50dp"
+                    android:layout_weight="1" >
+
+                    <ImageView
+                        android:id="@+id/action_indicator"
+                        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"
+                        android:visibility="invisible" />
+
+                    <TextView
+                        android:id="@+id/status_text"
+                        android:layout_width="wrap_content"
+                        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_height="0dp"
+                    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/oauth2_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/oauth2_url_endpoint_access"
+	                android:singleLine="true"
+	                android:visibility="gone" >
+	
+	                <requestFocus />
+	            </EditText>            
+	
+                <EditText
+                    android:id="@+id/account_username"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    android:layout_weight="1"
+                    android:ems="10"
+                    android:hint="@string/auth_username"
+                    android:inputType="textNoSuggestions" />
+
+                <FrameLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1" >
+
+                    <EditText
+                        android:id="@+id/account_password"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:ems="10"
+                        android:hint="@string/auth_password"
+                        android:inputType="textPassword"/>
+
+                    <ImageView
+                        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>
+                
+	            <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>
+            
+        </LinearLayout>
+    </FrameLayout>
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true" >
+
+        <LinearLayout
+            android:id="@+id/buttons_layout"        
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:weightSum="1">
+
+            <Button
+                android:id="@+id/buttonOK"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_weight=".5"
+                android:layout_marginLeft="16dip"
+		        android:layout_marginRight="16dip"
+                android:enabled="false"
+                android:onClick="onOkClick"
+                android:text="@string/setup_btn_connect"
+                android:textColor="@android:color/black" />
+            
+        </LinearLayout>
+        
+		<Button
+			android:id="@+id/account_register"
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:layout_below="@id/buttons_layout"
+			android:layout_centerHorizontal="true"
+			android:onClick="onRegisterClick"
+			android:paddingTop="10dp"
+			android:paddingBottom="10dp"
+			android:textColor="#0000FF"
+			android:background="@android:color/transparent" />
+			<!-- android:text="@string/app_name @string/auth_register" /-->
+        
+    </RelativeLayout>
+
+</LinearLayout>

+ 253 - 189
res/layout/account_setup.xml

@@ -1,189 +1,253 @@
-<?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 version 2,
-  as published by the Free Software Foundation.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program.  If not, see <http://www.gnu.org/licenses/>.
--->
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:orientation="vertical">
-    
-	<LinearLayout
-	    android:layout_width="fill_parent"
-	    android:layout_height="wrap_content"
-	    android:layout_gravity="center"
-	    android:focusable="true"
-	    android:gravity="center"
-	    android:orientation="vertical" >
-	    
-	    <FrameLayout
-	        android:layout_width="match_parent"
-	        android:layout_height="0dip"
-	        android:layout_gravity="center"
-	        android:layout_marginBottom="50dip"
-	        android:layout_marginLeft="16dip"
-	        android:layout_marginRight="16dip"
-	        android:layout_weight="1" >
-	
-	        <LinearLayout
-	            android:id="@+id/LinearLayout1"
-	            android:layout_width="match_parent"
-	            android:layout_height="wrap_content"
-	            android:layout_gravity="center"
-	            android:orientation="vertical" >
-	
-	            <ImageView
-	                android:id="@+id/imageView1"
-	                android:layout_width="match_parent"
-	                android:layout_height="wrap_content"
-	                android:layout_marginBottom="10dp"
-	                android:layout_weight="1"
-	                android:src="@drawable/owncloud_logo" />
-	
-	            <FrameLayout
-	                android:layout_width="match_parent"
-	                android:layout_height="wrap_content"
-	                android:layout_weight="1" >
-	
-	                <EditText
-	                    android:id="@+id/host_URL"
-	                    android:layout_width="match_parent"
-	                    android:layout_height="wrap_content"
-	                    android:ems="10"
-	                    android:hint="@string/auth_host_url"
-	                    android:inputType="textNoSuggestions" >
-	                    <requestFocus />
-	                </EditText>
-	
-	                <ImageView
-	                    android:id="@+id/refreshButton"
-	                    android:layout_width="wrap_content"
-	                    android:layout_height="wrap_content"
-	                    android:src="@drawable/ic_action_refresh_black"
-	                    android:layout_gravity="right|center_vertical"
-	                    android:visibility="invisible" />
-	
-	            </FrameLayout>
-	
-	            <LinearLayout
-	                android:layout_width="match_parent"
-	                android:layout_height="50dp"
-	                android:layout_weight="1" >
-	
-	                <ImageView
-	                    android:id="@+id/action_indicator"
-	                    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"
-	                    android:visibility="invisible" />
-	
-	                <TextView
-	                    android:id="@+id/status_text"
-	                    android:layout_width="wrap_content"
-	                    android:layout_height="wrap_content"
-	                    android:text="TextView"
-	                    android:visibility="invisible" />
-	
-	            </LinearLayout>
-	
-	            <TextView
-	                android:id="@+id/textView2"
-	                android:layout_width="wrap_content"
-	                android:layout_height="0dp"
-	                android:layout_weight="1"
-	                android:text="@string/auth_login_details"
-	                android:textAppearance="?android:attr/textAppearanceSmall" />
-	
-	            <EditText
-	                android:id="@+id/account_username"
-	                android:layout_width="match_parent"
-	                android:layout_height="0dp"
-	                android:layout_weight="1"
-	                android:ems="10"
-	                android:hint="@string/auth_username"
-	                android:inputType="textNoSuggestions" />
-	
-	            <FrameLayout
-	                android:layout_width="match_parent"
-	                android:layout_height="wrap_content"
-	                android:layout_weight="1" >
-	
-	                <EditText
-	                    android:id="@+id/account_password"
-	                    android:layout_width="match_parent"
-	                    android:layout_height="wrap_content"
-	                    android:ems="10"
-	                    android:hint="@string/auth_password"
-	                    android:inputType="textPassword"/>
-	
-	                <ImageView
-	                    android:id="@+id/viewPassword"
-	                    android:layout_width="wrap_content"
-	                    android:layout_height="wrap_content"
-	                    android:layout_gravity="right|center_vertical"
-	                    android:src="@android:drawable/ic_menu_view"
-	                    android:visibility="invisible" />
-	
-	            </FrameLayout>
-	
-	            </LinearLayout>
-	
-	    </FrameLayout>
-	
-	    <RelativeLayout
-	        android:layout_width="match_parent"
-	        android:layout_height="wrap_content">
-	
-	        <LinearLayout
-	            android:id="@+id/buttons_layout"
-	            android:layout_width="fill_parent"
-	            android:layout_height="wrap_content"
-	            android:weightSum="1">
-	
-	            <Button
-	                android:id="@+id/buttonOK"
-	                android:layout_width="match_parent"
-	                android:layout_height="wrap_content"
-		            android:layout_gravity="center_horizontal"
-		           	android:layout_marginLeft="16dip"
-		            android:layout_marginRight="16dip"
-	                android:enabled="false"
-	                android:onClick="onOkClick"
-	                android:text="@string/setup_btn_connect"
-	                android:textColor="@android:color/black" />
-	
-	        </LinearLayout>
-	        
-			<Button
-				android:id="@+id/account_register"
-				android:layout_width="wrap_content"
-				android:layout_height="wrap_content"
-				android:layout_below="@id/buttons_layout"
-				android:layout_centerHorizontal="true"
-				android:onClick="onRegisterClick"
-				android:paddingTop="10dp"
-				android:paddingBottom="10dp"
-				android:textColor="#0000FF"
-				android:background="@android:color/transparent" />
-	        
-	    </RelativeLayout>
-	    
-	</LinearLayout>
-	
-</ScrollView>
+<?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 version 2,
+  as published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+	<LinearLayout
+	    android:layout_width="match_parent"
+	    android:layout_height="wrap_content"
+	    android:layout_gravity="center"
+	    android:focusable="true"
+	    android:gravity="center"
+	    android:orientation="vertical" >
+
+    	<FrameLayout
+			android:layout_width="match_parent"
+			android:layout_height="0dip"
+			android:layout_gravity="center"
+			android:layout_marginBottom="50dip"
+			android:layout_marginLeft="16dip"
+			android:layout_marginRight="16dip"
+			android:layout_weight="1" >
+		
+			<LinearLayout
+				android:id="@+id/LinearLayout1"
+				android:layout_width="match_parent"
+				android:layout_height="wrap_content"
+				android:layout_gravity="center"
+				android:orientation="vertical" >
+		
+				<ImageView
+					android:id="@+id/imageView1"
+					android:layout_width="match_parent"
+					android:layout_height="wrap_content"
+					android:layout_marginBottom="10dp"
+					android:layout_weight="1"
+					android:src="@drawable/owncloud_logo" />
+		
+	            <FrameLayout
+	                android:layout_width="match_parent"
+	                android:layout_height="wrap_content"
+	                android:layout_weight="1" >
+	
+	                <EditText
+	                    android:id="@+id/hostUrlInput"
+	                    android:layout_width="match_parent"
+	                    android:layout_height="wrap_content"
+	                    android:ems="10"
+	                    android:hint="@string/auth_host_url"
+	                    android:inputType="textNoSuggestions" >
+	                    <requestFocus />
+	                </EditText>
+	
+	                <ImageView
+	                    android:id="@+id/refreshButton"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:src="@drawable/ic_action_refresh_black"
+	                    android:layout_gravity="right|center_vertical"
+	                    android:visibility="invisible" />
+	
+	            </FrameLayout>
+	
+	            <LinearLayout
+	                android:layout_width="match_parent"
+	                android:layout_height="50dp"
+	                android:layout_weight="1" >
+	
+	                <ImageView
+	                    android:id="@+id/action_indicator"
+	                    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"
+	                    android:visibility="invisible" />
+	
+	                <TextView
+	                    android:id="@+id/status_text"
+	                    android:layout_width="wrap_content"
+	                    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_height="0dp"
+	                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:text="@string/oauth2_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:text="@string/oauth2_url_endpoint_access"
+	                android:singleLine="true"
+	                android:visibility="gone" >
+	
+	                <requestFocus />
+	            </EditText>            
+	
+				<EditText
+	                android:id="@+id/account_username"
+	                android:layout_width="match_parent"
+	                android:layout_height="0dp"
+	                android:layout_weight="1"
+	                android:ems="10"
+	                android:hint="@string/auth_username"
+	                android:inputType="textNoSuggestions" />
+	
+	            <FrameLayout
+	                android:layout_width="match_parent"
+	                android:layout_height="wrap_content"
+	                android:layout_weight="1" >
+	
+	                <EditText
+	                    android:id="@+id/account_password"
+	                    android:layout_width="match_parent"
+	                    android:layout_height="wrap_content"
+	                    android:ems="10"
+	                    android:hint="@string/auth_password"
+	                    android:inputType="textPassword"/>
+	
+	                <ImageView
+	                    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>
+		
+	            <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>
+	
+	    <RelativeLayout
+	        android:layout_width="match_parent"
+	        android:layout_height="wrap_content">
+	
+	        <LinearLayout
+	            android:id="@+id/buttons_layout"
+	            android:layout_width="match_parent"
+	            android:layout_height="wrap_content"
+	            android:weightSum="1">
+	
+	            <Button
+	                android:id="@+id/buttonOK"
+	                android:layout_width="match_parent"
+	                android:layout_height="wrap_content"
+		            android:layout_gravity="center_horizontal"
+		           	android:layout_marginLeft="16dip"
+		            android:layout_marginRight="16dip"
+	                android:enabled="false"
+	                android:onClick="onOkClick"
+	                android:text="@string/setup_btn_connect"
+	                android:textColor="@android:color/black" />
+	
+	        </LinearLayout>
+	        
+			<Button
+				android:id="@+id/account_register"
+				android:layout_width="wrap_content"
+				android:layout_height="wrap_content"
+				android:layout_below="@id/buttons_layout"
+				android:layout_centerHorizontal="true"
+				android:onClick="onRegisterClick"
+				android:paddingTop="10dp"
+				android:paddingBottom="10dp"
+				android:textColor="#0000FF"
+				android:background="@android:color/transparent" />
+			
+			<Button
+				android:id="@+id/account_register"
+				android:layout_width="wrap_content"
+				android:layout_height="wrap_content"
+				android:layout_below="@id/buttons_layout"
+				android:layout_centerHorizontal="true"
+				android:onClick="onRegisterClick"
+				android:paddingTop="10dp"
+				android:paddingBottom="10dp"
+				android:textColor="#0000FF"
+				android:background="@android:color/transparent" />
+				<!-- android:text="@string/app_name @string/auth_register" /-->
+	        
+	    </RelativeLayout>
+
+	</LinearLayout>
+			
+</ScrollView>

+ 23 - 0
res/values/oauth2_configuration.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <!-- Flag to configure OAuth availability in the app.
+    	 3 valid values now: on, off, optional	
+     -->
+    <string name="oauth2_mode">off</string>
+    
+    <!-- constants that must be respected by the authorization server; if changed, the app must be rebuild -->
+    <string name="oauth2_redirect_scheme">owncloud</string>
+    <string name="oauth2_redirect_uri">owncloud://callback</string>
+    
+    <!-- values that should be provided by ownCloud server -->
+    <string name="oauth2_url_endpoint_auth">http://oauth2.authorization.server.org/paht/to/endpoint/for/authorization</string>
+    <string name="oauth2_url_endpoint_access">http://oauth2.authorization.server.org/paht/to/endporint/for/access/token</string>
+    <string name="oauth2_scope">owncloud</string>
+    <string name="oauth2_grant_type">authorization_code</string>	<!-- the only one supported right now -->
+    <string name="oauth2_response_type">code</string>				<!-- depends on oauth2_grant_type -->
+    
+    <!-- values that should be pre-agreed between app and authorization server, but can be loaded without rebuilding the app -->
+    <string name="oauth2_client_id">com.owncloud.android</string>	<!-- preferable that client decides this -->
+    <string name="oauth2_client_secret"></string>					<!-- preferable that client decides this -->
+    
+</resources>

+ 17 - 3
res/values/strings.xml

@@ -118,8 +118,9 @@
     <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_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_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="sync_fail_in_favourites_content">Contents of %1$d files could not be sync\'ed (%2$d conflicts)</string>
     <string name="sync_foreign_files_forgotten_ticker">Some local files were forgotten</string>
@@ -200,9 +201,15 @@
     <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="crashlog_dont_send_report">Don\'t send report</string>
@@ -229,6 +236,13 @@
     <string name="wait_a_moment">Wait a moment</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>

+ 4 - 0
res/values/styles.xml

@@ -101,6 +101,10 @@
 		<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>

+ 8 - 3
src/com/owncloud/android/AccountUtils.java

@@ -18,7 +18,7 @@
 
 package com.owncloud.android;
 
-import com.owncloud.android.authenticator.AccountAuthenticator;
+import com.owncloud.android.authentication.AccountAuthenticator;
 import com.owncloud.android.utils.OwnCloudVersion;
 
 import android.accounts.Account;
@@ -31,6 +31,7 @@ public class AccountUtils {
     public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php";
     public static final String WEBDAV_PATH_2_0 = "/files/webdav.php";
     public static final String WEBDAV_PATH_4_0 = "/remote.php/webdav";
+    private static final String ODAV_PATH = "/remote.php/odav";
     public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php";
     public static final String CARDDAV_PATH_4_0 = "/remote/carddav.php";
     public static final String STATUS_PATH = "/status.php";
@@ -112,8 +113,11 @@ public class AccountUtils {
      * @param version version of owncloud
      * @return webdav path for given OC version, null if OC version unknown
      */
-    public static String getWebdavPath(OwnCloudVersion version) {
+    public static String getWebdavPath(OwnCloudVersion version, boolean supportsOAuth) {
         if (version != null) {
+            if (supportsOAuth) {
+                return ODAV_PATH;
+            }
             if (version.compareTo(OwnCloudVersion.owncloud_v4) >= 0)
                 return WEBDAV_PATH_4_0;
             if (version.compareTo(OwnCloudVersion.owncloud_v3) >= 0
@@ -136,8 +140,9 @@ public class AccountUtils {
             AccountManager ama = AccountManager.get(context);
             String baseurl = ama.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL);
             String strver  = ama.getUserData(account, AccountAuthenticator.KEY_OC_VERSION);
+            boolean supportsOAuth = (ama.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null);
             OwnCloudVersion ver = new OwnCloudVersion(strver);
-            String webdavpath = getWebdavPath(ver);
+            String webdavpath = getWebdavPath(ver, supportsOAuth);
 
             if (webdavpath == null) return null;
             return baseurl + webdavpath;

+ 0 - 2
src/com/owncloud/android/DisplayUtils.java

@@ -24,8 +24,6 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Set;
 
-import android.util.Log;
-
 /**
  * A helper class for some string operations.
  * 

+ 6 - 7
src/com/owncloud/android/Uploader.java

@@ -15,6 +15,7 @@
  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
+
 package com.owncloud.android;
 
 import java.io.File;
@@ -25,12 +26,11 @@ import java.util.List;
 import java.util.Stack;
 import java.util.Vector;
 
-import com.owncloud.android.authenticator.AccountAuthenticator;
+import com.owncloud.android.authentication.AccountAuthenticator;
 import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileUploader;
-import com.owncloud.android.network.OwnCloudClientUtils;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
@@ -49,7 +49,6 @@ import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.provider.MediaStore.Images.Media;
-import android.util.Log;
 import android.view.View;
 import android.view.Window;
 import android.widget.AdapterView;
@@ -60,7 +59,6 @@ import android.widget.SimpleAdapter;
 import android.widget.Toast;
 
 import com.owncloud.android.R;
-import eu.alefzero.webdav.WebdavClient;
 
 /**
  * This can be used to upload things to an ownCloud instance.
@@ -140,8 +138,8 @@ public class Uploader extends ListActivity implements OnItemClickListener, andro
                         // in API7 < this constatant is defined in
                         // Settings.ADD_ACCOUNT_SETTINGS
                         // and Settings.EXTRA_AUTHORITIES
-                        Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");
-                        intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });
+                        Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);
+                        intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTHORITY });
                         startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
                     } else {
                         // since in API7 there is no direct call for
@@ -357,12 +355,13 @@ public class Uploader extends ListActivity implements OnItemClickListener, andro
 
     public void uploadFiles() {
         try {
+            /* TODO - mCreateDir can never be true at this moment; we will replace wdc.createDirectory by CreateFolderOperation when that is fixed 
             WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext());
-
             // create last directory in path if necessary
             if (mCreateDir) {
                 wdc.createDirectory(mUploadPath);
             }
+            */
 
             String[] local = new String[mStreamsToUpload.size()], remote = new String[mStreamsToUpload.size()];
 

+ 144 - 111
src/com/owncloud/android/authenticator/AccountAuthenticator.java → src/com/owncloud/android/authentication/AccountAuthenticator.java

@@ -16,33 +16,46 @@
  *
  */
 
-package com.owncloud.android.authenticator;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.ui.activity.AuthenticatorActivity;
+package com.owncloud.android.authentication;
 
 import android.accounts.*;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
-import android.util.Log;
+import com.owncloud.android.Log_OC;
 
+/**
+ *  Authenticator for ownCloud accounts.
+ * 
+ *  Controller class accessed from the system AccountManager, providing integration of ownCloud accounts with the Android system.
+ * 
+ *  TODO - better separation in operations for OAuth-capable and regular ownCloud accounts.
+ *  TODO - review completeness 
+ * 
+ * @author David A. Velasco
+ */
 public class AccountAuthenticator extends AbstractAccountAuthenticator {
+    
     /**
      * Is used by android system to assign accounts to authenticators. Should be
      * used by application and all extensions.
      */
     public static final String ACCOUNT_TYPE = "owncloud";
+    public static final String AUTHORITY = "org.owncloud";
     public static final String AUTH_TOKEN_TYPE = "org.owncloud";
+    public static final String AUTH_TOKEN_TYPE_PASSWORD = "owncloud.password";
+    public static final String AUTH_TOKEN_TYPE_ACCESS_TOKEN = "owncloud.oauth2.access_token";
+    public static final String AUTH_TOKEN_TYPE_REFRESH_TOKEN = "owncloud.oauth2.refresh_token";
 
     public static final String KEY_AUTH_TOKEN_TYPE = "authTokenType";
     public static final String KEY_REQUIRED_FEATURES = "requiredFeatures";
     public static final String KEY_LOGIN_OPTIONS = "loginOptions";
     public static final String KEY_ACCOUNT = "account";
+    
     /**
      * Value under this key should handle path to webdav php script. Will be
      * removed and usage should be replaced by combining
-     * {@link com.owncloud.android.authenticator.AuthenticatorActivity.KEY_OC_BASE_URL} and
+     * {@link com.owncloud.android.authentication.AuthenticatorActivity.KEY_OC_BASE_URL} and
      * {@link com.owncloud.android.utils.OwnCloudVersion}
      * 
      * @deprecated
@@ -58,8 +71,13 @@ public class AccountAuthenticator extends AbstractAccountAuthenticator {
      * http://server/path or https://owncloud.server
      */
     public static final String KEY_OC_BASE_URL = "oc_base_url";
-
-    private static final String TAG = "AccountAuthenticator";
+    /**
+     * Flag signaling if the ownCloud server can be accessed with OAuth2 access tokens.
+     */
+    public static final String KEY_SUPPORTS_OAUTH2 = "oc_supports_oauth2";
+    
+    private static final String TAG = AccountAuthenticator.class.getSimpleName();
+    
     private Context mContext;
 
     public AccountAuthenticator(Context context) {
@@ -86,55 +104,60 @@ public class AccountAuthenticator extends AbstractAccountAuthenticator {
             return e.getFailureBundle();
         }
         final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
-        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
-                response);
+        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
         intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
         intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures);
         intent.putExtra(KEY_LOGIN_OPTIONS, options);
+        intent.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_CREATE);
 
         setIntentFlags(intent);
+        
         final Bundle bundle = new Bundle();
         bundle.putParcelable(AccountManager.KEY_INTENT, intent);
         return bundle;
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Bundle confirmCredentials(AccountAuthenticatorResponse response,
+            Account account, Bundle options) throws NetworkErrorException {
+        try {
+            validateAccountType(account.type);
+        } catch (AuthenticatorException e) {
+            Log_OC.e(TAG, "Failed to validate account type " + account.type + ": "
+                    + e.getMessage());
+            e.printStackTrace();
+            return e.getFailureBundle();
+        }
+        Intent intent = new Intent(mContext, AuthenticatorActivity.class);
+        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
+                response);
+        intent.putExtra(KEY_ACCOUNT, account);
+        intent.putExtra(KEY_LOGIN_OPTIONS, options);
+
+        setIntentFlags(intent);
+
+        Bundle resultBundle = new Bundle();
+        resultBundle.putParcelable(AccountManager.KEY_INTENT, intent);
+        return resultBundle;
+    }
+
+    @Override
+    public Bundle editProperties(AccountAuthenticatorResponse response,
+            String accountType) {
+        return null;
+    }
+
     /**
      * {@inheritDoc}
      */
-    @Override
-    public Bundle confirmCredentials(AccountAuthenticatorResponse response,
-            Account account, Bundle options) throws NetworkErrorException {
-        try {
-            validateAccountType(account.type);
-        } catch (AuthenticatorException e) {
-            Log_OC.e(TAG, "Failed to validate account type " + account.type + ": "
-                    + e.getMessage());
-            e.printStackTrace();
-            return e.getFailureBundle();
-        }
-        Intent intent = new Intent(mContext, AuthenticatorActivity.class);
-        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
-                response);
-        intent.putExtra(KEY_ACCOUNT, account);
-        intent.putExtra(KEY_LOGIN_OPTIONS, options);
-
-        setIntentFlags(intent);
-
-        Bundle resultBundle = new Bundle();
-        resultBundle.putParcelable(AccountManager.KEY_INTENT, intent);
-        return resultBundle;
-    }
-
-    @Override
-    public Bundle editProperties(AccountAuthenticatorResponse response,
-            String accountType) {
-        return null;
-    }
-
     @Override
     public Bundle getAuthToken(AccountAuthenticatorResponse response,
             Account account, String authTokenType, Bundle options)
             throws NetworkErrorException {
+        /// validate parameters
         try {
             validateAccountType(account.type);
             validateAuthTokenType(authTokenType);
@@ -144,22 +167,31 @@ public class AccountAuthenticator extends AbstractAccountAuthenticator {
             e.printStackTrace();
             return e.getFailureBundle();
         }
+        
+        /// check if required token is stored
         final AccountManager am = AccountManager.get(mContext);
-        final String password = am.getPassword(account);
-        if (password != null) {
+        String accessToken;
+        if (authTokenType.equals(AUTH_TOKEN_TYPE_PASSWORD)) {
+            accessToken = am.getPassword(account);
+        } else {
+            accessToken = am.peekAuthToken(account, authTokenType);
+        }
+        if (accessToken != null) {
             final Bundle result = new Bundle();
             result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
             result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);
-            result.putString(AccountManager.KEY_AUTHTOKEN, password);
+            result.putString(AccountManager.KEY_AUTHTOKEN, accessToken);
             return result;
         }
-
+        
+        /// if not stored, return Intent to access the AuthenticatorActivity and UPDATE the token for the account
         final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
-        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
-                response);
+        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
         intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
         intent.putExtra(KEY_LOGIN_OPTIONS, options);
-        intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name);
+        intent.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, account);
+        intent.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);
+        
 
         final Bundle bundle = new Bundle();
         bundle.putParcelable(AccountManager.KEY_INTENT, intent);
@@ -205,8 +237,6 @@ public class AccountAuthenticator extends AbstractAccountAuthenticator {
 
     private void setIntentFlags(Intent intent) {
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
         intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
         intent.addFlags(Intent.FLAG_FROM_BACKGROUND);
     }
@@ -218,65 +248,68 @@ public class AccountAuthenticator extends AbstractAccountAuthenticator {
         }
     }
 
-    private void validateAuthTokenType(String authTokenType)
-            throws UnsupportedAuthTokenTypeException {
-        if (!authTokenType.equals(AUTH_TOKEN_TYPE)) {
-            throw new UnsupportedAuthTokenTypeException();
-        }
-    }
-
-    public static class AuthenticatorException extends Exception {
-        private static final long serialVersionUID = 1L;
-        private Bundle mFailureBundle;
-
-        public AuthenticatorException(int code, String errorMsg) {
-            mFailureBundle = new Bundle();
-            mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code);
-            mFailureBundle
-                    .putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
-        }
-
-        public Bundle getFailureBundle() {
-            return mFailureBundle;
-        }
-    }
-
-    public static class UnsupportedAccountTypeException extends
-            AuthenticatorException {
-        private static final long serialVersionUID = 1L;
-
-        public UnsupportedAccountTypeException() {
-            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
-                    "Unsupported account type");
-        }
-    }
-
-    public static class UnsupportedAuthTokenTypeException extends
-            AuthenticatorException {
-        private static final long serialVersionUID = 1L;
-
-        public UnsupportedAuthTokenTypeException() {
-            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
-                    "Unsupported auth token type");
-        }
-    }
-
-    public static class UnsupportedFeaturesException extends
-            AuthenticatorException {
-        public static final long serialVersionUID = 1L;
-
-        public UnsupportedFeaturesException() {
-            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
-                    "Unsupported features");
-        }
-    }
-
-    public static class AccessDeniedException extends AuthenticatorException {
-        public AccessDeniedException(int code, String errorMsg) {
-            super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied");
-        }
-
-        private static final long serialVersionUID = 1L;
-
-    }
-}
+    private void validateAuthTokenType(String authTokenType)
+            throws UnsupportedAuthTokenTypeException {
+        if (!authTokenType.equals(AUTH_TOKEN_TYPE) &&
+            !authTokenType.equals(AUTH_TOKEN_TYPE_PASSWORD) &&
+            !authTokenType.equals(AUTH_TOKEN_TYPE_ACCESS_TOKEN) &&
+            !authTokenType.equals(AUTH_TOKEN_TYPE_REFRESH_TOKEN) ) {
+            throw new UnsupportedAuthTokenTypeException();
+        }
+    }
+
+    public static class AuthenticatorException extends Exception {
+        private static final long serialVersionUID = 1L;
+        private Bundle mFailureBundle;
+
+        public AuthenticatorException(int code, String errorMsg) {
+            mFailureBundle = new Bundle();
+            mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code);
+            mFailureBundle
+                    .putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+        }
+
+        public Bundle getFailureBundle() {
+            return mFailureBundle;
+        }
+    }
+
+    public static class UnsupportedAccountTypeException extends
+            AuthenticatorException {
+        private static final long serialVersionUID = 1L;
+
+        public UnsupportedAccountTypeException() {
+            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
+                    "Unsupported account type");
+        }
+    }
+
+    public static class UnsupportedAuthTokenTypeException extends
+            AuthenticatorException {
+        private static final long serialVersionUID = 1L;
+
+        public UnsupportedAuthTokenTypeException() {
+            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
+                    "Unsupported auth token type");
+        }
+    }
+
+    public static class UnsupportedFeaturesException extends
+            AuthenticatorException {
+        public static final long serialVersionUID = 1L;
+
+        public UnsupportedFeaturesException() {
+            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
+                    "Unsupported features");
+        }
+    }
+
+    public static class AccessDeniedException extends AuthenticatorException {
+        public AccessDeniedException(int code, String errorMsg) {
+            super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied");
+        }
+
+        private static final long serialVersionUID = 1L;
+
+    }
+}

+ 1 - 1
src/com/owncloud/android/authenticator/AccountAuthenticatorService.java → src/com/owncloud/android/authentication/AccountAuthenticatorService.java

@@ -16,7 +16,7 @@
  *
  */
 
-package com.owncloud.android.authenticator;
+package com.owncloud.android.authentication;
 
 import android.app.Service;
 import android.content.Intent;

+ 1085 - 0
src/com/owncloud/android/authentication/AuthenticatorActivity.java

@@ -0,0 +1,1085 @@
+/* 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 version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.authentication;
+
+import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.ui.dialog.SslValidatorDialog;
+import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;
+import com.owncloud.android.utils.OwnCloudVersion;
+import com.owncloud.android.network.OwnCloudClientUtils;
+import com.owncloud.android.operations.OwnCloudServerCheckOperation;
+import com.owncloud.android.operations.ExistenceCheckOperation;
+import com.owncloud.android.operations.OAuth2GetAccessToken;
+import com.owncloud.android.operations.OnRemoteOperationListener;
+import com.owncloud.android.operations.RemoteOperation;
+import com.owncloud.android.operations.RemoteOperationResult;
+import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
+
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorActivity;
+import android.accounts.AccountManager;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.ContentResolver;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.preference.PreferenceManager;
+import android.text.InputType;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+import android.view.Window;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.owncloud.android.R;
+
+import eu.alefzero.webdav.WebdavClient;
+
+/**
+ * This Activity is used to add an ownCloud account to the App
+ * 
+ * @author Bartek Przybylski
+ * @author David A. Velasco
+ */
+public class AuthenticatorActivity extends AccountAuthenticatorActivity
+        implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeListener {
+
+    private static final String TAG = AuthenticatorActivity.class.getSimpleName();
+
+    public static final String EXTRA_ACCOUNT = "ACCOUNT";
+    public static final String EXTRA_USER_NAME = "USER_NAME";
+    public static final String EXTRA_HOST_NAME = "HOST_NAME";
+    public static final String EXTRA_ACTION = "ACTION";
+    
+    private static final String KEY_HOST_URL_TEXT = "HOST_URL_TEXT";
+    private static final String KEY_OC_VERSION = "OC_VERSION";
+    private static final String KEY_ACCOUNT = "ACCOUNT";
+    private static final String KEY_STATUS_TEXT = "STATUS_TEXT";
+    private static final String KEY_STATUS_ICON = "STATUS_ICON";
+    private static final String KEY_STATUS_CORRECT = "STATUS_CORRECT";
+    private static final String KEY_IS_SSL_CONN = "IS_SSL_CONN";
+    private static final String KEY_OAUTH2_STATUS_TEXT = "OAUTH2_STATUS_TEXT";
+    private static final String KEY_OAUTH2_STATUS_ICON = "OAUTH2_STATUS_ICON";
+    
+    private static final String OAUTH_MODE_ON = "on";
+    private static final String OAUTH_MODE_OFF = "off";
+    private static final String OAUTH_MODE_OPTIONAL = "optional";
+
+    private static final int DIALOG_LOGIN_PROGRESS = 0;
+    private static final int DIALOG_SSL_VALIDATOR = 1;
+    private static final int DIALOG_CERT_NOT_SAVED = 2;
+    private static final int DIALOG_OAUTH2_LOGIN_PROGRESS = 3;
+
+    public static final byte ACTION_CREATE = 0;
+    public static final byte ACTION_UPDATE_TOKEN = 1;
+
+    
+    private String mHostBaseUrl;
+    private OwnCloudVersion mDiscoveredVersion;
+    
+    private int mStatusText, mStatusIcon;
+    private boolean mStatusCorrect, mIsSslConn;
+    private int mOAuth2StatusText, mOAuth2StatusIcon;    
+    
+    private final Handler mHandler = new Handler();
+    private Thread mOperationThread;
+    private OwnCloudServerCheckOperation mOcServerChkOperation;
+    private ExistenceCheckOperation mAuthCheckOperation;
+    private RemoteOperationResult mLastSslUntrustedServerResult;
+
+    private Uri mNewCapturedUriFromOAuth2Redirection;
+    
+    private AccountManager mAccountMgr;
+    private boolean mJustCreated;
+    private byte mAction;
+    private Account mAccount;
+    
+    private ImageView mRefreshButton;
+    private ImageView mViewPasswordButton;
+    private EditText mHostUrlInput;
+    private EditText mUsernameInput;
+    private EditText mPasswordInput;
+    private CheckBox mOAuth2Check;
+    private String mOAuthAccessToken;
+    private View mOkButton;
+    private TextView mAuthStatusLayout;
+    
+    private TextView mOAuthAuthEndpointText;
+    private TextView mOAuthTokenEndpointText;
+    
+    
+    /**
+     * {@inheritDoc}
+     * 
+     * IMPORTANT ENTRY POINT 1: activity is shown to the user
+     */
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+        
+        /// set view and get references to view elements
+        setContentView(R.layout.account_setup);
+        mRefreshButton = (ImageView) findViewById(R.id.refreshButton);
+        mViewPasswordButton = (ImageView) findViewById(R.id.viewPasswordButton);
+        mHostUrlInput = (EditText) findViewById(R.id.hostUrlInput);
+        mUsernameInput = (EditText) findViewById(R.id.account_username);
+        mPasswordInput = (EditText) findViewById(R.id.account_password);
+        mOAuthAuthEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_1);
+        mOAuthTokenEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_2);
+        mOAuth2Check = (CheckBox) findViewById(R.id.oauth_onOff_check);
+        mOkButton = findViewById(R.id.buttonOK);
+        mAuthStatusLayout = (TextView) findViewById(R.id.auth_status_text); 
+        
+        /// complete label for 'register account' button
+        Button b = (Button) findViewById(R.id.account_register);
+        if (b != null) {
+            b.setText(String.format(getString(R.string.auth_register), getString(R.string.app_name)));
+        }
+
+        /// bind view elements to listeners
+        mHostUrlInput.setOnFocusChangeListener(this);
+        mPasswordInput.setOnFocusChangeListener(this);
+        
+        /// initialization
+        mAccountMgr = AccountManager.get(this);
+        mNewCapturedUriFromOAuth2Redirection = null;
+        mAction = getIntent().getByteExtra(EXTRA_ACTION, ACTION_CREATE); 
+        mAccount = null;
+
+        if (savedInstanceState == null) {
+            /// connection state and info
+            mStatusText = mStatusIcon = 0;
+            mStatusCorrect = false;
+            mIsSslConn = false;
+            
+            /// retrieve extras from intent
+            String tokenType = getIntent().getExtras().getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE);
+            boolean oAuthRequired = AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN.equals(tokenType) || OAUTH_MODE_ON.equals(getString(R.string.oauth2_mode));
+            
+            mAccount = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT);
+            if (mAccount != null) {
+                String ocVersion = mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION);
+                if (ocVersion != null) {
+                    mDiscoveredVersion = new OwnCloudVersion(ocVersion);
+                }
+                mHostBaseUrl = mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL);
+                mHostUrlInput.setText(mHostBaseUrl);
+                String userName = mAccount.name.substring(0, mAccount.name.lastIndexOf('@'));
+                mUsernameInput.setText(userName);
+                oAuthRequired = (mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null);
+            }
+            mOAuth2Check.setChecked(oAuthRequired);
+            changeViewByOAuth2Check(oAuthRequired);
+            
+
+        } else {
+            loadSavedInstanceState(savedInstanceState);
+        }
+        
+        if (!OAUTH_MODE_OPTIONAL.equals(getString(R.string.oauth2_mode))) {
+            mOAuth2Check.setVisibility(View.GONE);
+        }
+        
+        if (mAction == ACTION_UPDATE_TOKEN) {
+            /// lock things that should not change
+            mHostUrlInput.setEnabled(false);
+            mUsernameInput.setEnabled(false);
+            mOAuth2Check.setVisibility(View.GONE);
+            checkOcServer(); 
+        }
+        
+        mPasswordInput.setText("");     // clean password to avoid social hacking (disadvantage: password in removed if the device is turned aside)
+        mJustCreated = true;
+    }
+
+
+    /**
+     * Saves relevant state before {@link #onPause()}
+     * 
+     * Do NOT save {@link #mNewCapturedUriFromOAuth2Redirection}; it keeps a temporal flag, intended to defer the 
+     * processing of the redirection caught in {@link #onNewIntent(Intent)} until {@link #onResume()} 
+     * 
+     * See {@link #loadSavedInstanceState(Bundle)}
+     */
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        
+        /// connection state and info
+        outState.putInt(KEY_STATUS_TEXT, mStatusText);
+        outState.putInt(KEY_STATUS_ICON, mStatusIcon);
+        outState.putBoolean(KEY_STATUS_CORRECT, mStatusCorrect);
+        outState.putBoolean(KEY_IS_SSL_CONN, mIsSslConn);
+
+        /// server data
+        if (mDiscoveredVersion != null) 
+            outState.putString(KEY_OC_VERSION, mDiscoveredVersion.toString());
+        outState.putString(KEY_HOST_URL_TEXT, mHostBaseUrl);
+        
+        /// account data, if updating
+        if (mAccount != null)
+            outState.putParcelable(KEY_ACCOUNT, mAccount);
+        
+        // Saving the state of oAuth2 components.
+        outState.putInt(KEY_OAUTH2_STATUS_ICON, mOAuth2StatusIcon);
+        outState.putInt(KEY_OAUTH2_STATUS_TEXT, mOAuth2StatusText);
+        
+    }
+
+
+    /**
+     * Loads saved state
+     * 
+     * See {@link #onSaveInstanceState(Bundle)}.
+     * 
+     * @param savedInstanceState    Saved state, as received in {@link #onCreate(Bundle)}.
+     */
+    private void loadSavedInstanceState(Bundle savedInstanceState) {
+        /// connection state and info
+        mStatusCorrect = savedInstanceState.getBoolean(KEY_STATUS_CORRECT);
+        mIsSslConn = savedInstanceState.getBoolean(KEY_IS_SSL_CONN);
+        mStatusText = savedInstanceState.getInt(KEY_STATUS_TEXT);
+        mStatusIcon = savedInstanceState.getInt(KEY_STATUS_ICON);
+        updateConnStatus();
+        
+        /// UI settings depending upon connection
+        mOkButton.setEnabled(mStatusCorrect);   // TODO really necessary?
+        if (!mStatusCorrect)
+            mRefreshButton.setVisibility(View.VISIBLE); // seems that setting visibility is necessary
+        else
+            mRefreshButton.setVisibility(View.INVISIBLE);
+        
+        /// server data
+        String ocVersion = savedInstanceState.getString(KEY_OC_VERSION);
+        if (ocVersion != null)
+            mDiscoveredVersion = new OwnCloudVersion(ocVersion);
+        mHostBaseUrl = savedInstanceState.getString(KEY_HOST_URL_TEXT);
+        
+        // account data, if updating
+        mAccount = savedInstanceState.getParcelable(KEY_ACCOUNT);
+        
+        // state of oAuth2 components
+        mOAuth2StatusIcon = savedInstanceState.getInt(KEY_OAUTH2_STATUS_ICON);
+        mOAuth2StatusText = savedInstanceState.getInt(KEY_OAUTH2_STATUS_TEXT);
+        // END of getting the state of oAuth2 components.
+    }
+
+    
+    /**
+     * The redirection triggered by the OAuth authentication server as response to the GET AUTHORIZATION request
+     * is caught here.
+     * 
+     * To make this possible, this activity needs to be qualified with android:launchMode = "singleTask" in the
+     * AndroidManifest.xml file.
+     */
+    @Override
+    protected void onNewIntent (Intent intent) {
+        Log_OC.d(TAG, "onNewIntent()");
+        Uri data = intent.getData();
+        if (data != null && data.toString().startsWith(getString(R.string.oauth2_redirect_uri))) {
+            mNewCapturedUriFromOAuth2Redirection = data;
+        }
+    }
+
+    
+    /**
+     * The redirection triggered by the OAuth authentication server as response to the GET AUTHORIZATION, and 
+     * deferred in {@link #onNewIntent(Intent)}, is processed here.
+     */
+    @Override
+    protected void onResume() {
+        super.onResume();
+        // the state of mOAuth2Check is automatically recovered between configuration changes, but not before onCreate() finishes; so keep the next lines here
+        changeViewByOAuth2Check(mOAuth2Check.isChecked());  
+        if (mAction == ACTION_UPDATE_TOKEN && mJustCreated) {
+            if (mOAuth2Check.isChecked())
+                Toast.makeText(this, R.string.auth_expired_oauth_token_toast, Toast.LENGTH_LONG).show();
+            else
+                Toast.makeText(this, R.string.auth_expired_basic_auth_toast, Toast.LENGTH_LONG).show();
+        }
+        
+        if (mNewCapturedUriFromOAuth2Redirection != null) {
+            getOAuth2AccessTokenFromCapturedRedirection();            
+        }
+        
+        mJustCreated = false;
+    }
+    
+    
+    /**
+     * Parses the redirection with the response to the GET AUTHORIZATION request to the 
+     * oAuth server and requests for the access token (GET ACCESS TOKEN)
+     */
+    private void getOAuth2AccessTokenFromCapturedRedirection() {
+        /// Parse data from OAuth redirection
+        String queryParameters = mNewCapturedUriFromOAuth2Redirection.getQuery();
+        mNewCapturedUriFromOAuth2Redirection = null;
+        
+        /// Showing the dialog with instructions for the user.
+        showDialog(DIALOG_OAUTH2_LOGIN_PROGRESS);
+
+        /// GET ACCESS TOKEN to the oAuth server 
+        RemoteOperation operation = new OAuth2GetAccessToken(   getString(R.string.oauth2_client_id), 
+                                                                getString(R.string.oauth2_redirect_uri), // TODO check - necessary here?      
+                                                                getString(R.string.oauth2_grant_type),
+                                                                queryParameters);
+        //WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(getString(R.string.oauth2_url_endpoint_access)), getApplicationContext());
+        WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mOAuthTokenEndpointText.getText().toString().trim()), getApplicationContext());
+        operation.execute(client, this, mHandler);
+    }
+    
+
+    
+    /**
+     * Handles the change of focus on the text inputs for the server URL and the password
+     */
+    public void onFocusChange(View view, boolean hasFocus) {
+        if (view.getId() == R.id.hostUrlInput) {
+            onUrlInputFocusChanged((TextView) view, hasFocus);
+            
+        } else if (view.getId() == R.id.account_password) {
+            onPasswordFocusChanged((TextView) view, hasFocus);
+        }
+    }
+    
+
+    /**
+     * Handles changes in focus on the text input for the server URL.
+     * 
+     * IMPORTANT ENTRY POINT 2: When (!hasFocus), user wrote the server URL and changed to 
+     * other field. The operation to check the existence of the server in the entered URL is
+     * started. 
+     * 
+     * When hasFocus:    user 'comes back' to write again the server URL.
+     * 
+     * @param hostInput     TextView with the URL input field receiving the change of focus.
+     * @param hasFocus      'True' if focus is received, 'false' if is lost
+     */
+    private void onUrlInputFocusChanged(TextView hostInput, boolean hasFocus) {
+        if (!hasFocus) {
+            checkOcServer();
+            
+        } else {
+            // avoids that the 'connect' button can be clicked if the test was previously passed
+            mOkButton.setEnabled(false); 
+        }
+    }
+
+
+    private void checkOcServer() {
+        String uri = mHostUrlInput.getText().toString().trim();
+        if (uri.length() != 0) {
+            mStatusText = R.string.auth_testing_connection;
+            mStatusIcon = R.drawable.progress_small;
+            updateConnStatus();
+            /** TODO cancel previous connection check if the user tries to ammend a wrong URL  
+            if(mConnChkOperation != null) {
+                mConnChkOperation.cancel();
+            } */
+            mOcServerChkOperation = new  OwnCloudServerCheckOperation(uri, this);
+            WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this);
+            mHostBaseUrl = "";
+            mDiscoveredVersion = null;
+            mOperationThread = mOcServerChkOperation.execute(client, this, mHandler);
+        } else {
+            mRefreshButton.setVisibility(View.INVISIBLE);
+            mStatusText = 0;
+            mStatusIcon = 0;
+            updateConnStatus();
+        }
+    }
+
+
+    /**
+     * Handles changes in focus on the text input for the password (basic authorization).
+     * 
+     * When (hasFocus), the button to toggle password visibility is shown.
+     * 
+     * When (!hasFocus), the button is made invisible and the password is hidden.
+     * 
+     * @param passwordInput    TextView with the password input field receiving the change of focus.
+     * @param hasFocus          'True' if focus is received, 'false' if is lost
+     */
+    private void onPasswordFocusChanged(TextView passwordInput, boolean hasFocus) {
+        if (hasFocus) {
+            mViewPasswordButton.setVisibility(View.VISIBLE);
+        } else {
+            int input_type = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD;
+            passwordInput.setInputType(input_type);
+            mViewPasswordButton.setVisibility(View.INVISIBLE);
+        }
+    }
+
+
+    
+    /**
+     * Cancels the authenticator activity
+     * 
+     * IMPORTANT ENTRY POINT 3: Never underestimate the importance of cancellation
+     * 
+     * This method is bound in the layout/acceoun_setup.xml resource file.
+     * 
+     * @param view      Cancel button
+     */
+    public void onCancelClick(View view) {
+        setResult(RESULT_CANCELED);     // TODO review how is this related to AccountAuthenticator (debugging)
+        finish();
+    }
+    
+    
+    
+    /**
+     * Checks the credentials of the user in the root of the ownCloud server
+     * before creating a new local account.
+     * 
+     * For basic authorization, a check of existence of the root folder is
+     * performed.
+     * 
+     * For OAuth, starts the flow to get an access token; the credentials test 
+     * is postponed until it is available.
+     * 
+     * IMPORTANT ENTRY POINT 4
+     * 
+     * @param view      OK button
+     */
+    public void onOkClick(View view) {
+        // this check should be unnecessary
+        if (mDiscoveredVersion == null || !mDiscoveredVersion.isVersionValid()  || mHostBaseUrl == null || mHostBaseUrl.length() == 0) {
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_wtf_reenter_URL;
+            updateConnStatus();
+            mOkButton.setEnabled(false);
+            Log_OC.wtf(TAG,  "The user was allowed to click 'connect' to an unchecked server!!");
+            return;
+        }
+        
+        if (mOAuth2Check.isChecked()) {
+            startOauthorization();
+            
+        } else {
+            checkBasicAuthorization();
+        }
+    }
+    
+    
+    /**
+     * Tests the credentials entered by the user performing a check of existence on 
+     * the root folder of the ownCloud server.
+     */
+    private void checkBasicAuthorization() {
+        /// get the path to the root folder through WebDAV from the version server
+        String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, false);
+        
+        /// get basic credentials entered by user
+        String username = mUsernameInput.getText().toString();
+        String password = mPasswordInput.getText().toString();
+        
+        /// be gentle with the user
+        showDialog(DIALOG_LOGIN_PROGRESS);
+        
+        /// test credentials accessing the root folder
+        mAuthCheckOperation = new  ExistenceCheckOperation("", this, false);
+        WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this);
+        client.setBasicCredentials(username, password);
+        mOperationThread = mAuthCheckOperation.execute(client, this, mHandler);
+    }
+
+
+    /**
+     * Starts the OAuth 'grant type' flow to get an access token, with 
+     * a GET AUTHORIZATION request to the BUILT-IN authorization server. 
+     */
+    private void startOauthorization() {
+        // be gentle with the user
+        mStatusIcon = R.drawable.progress_small;
+        mStatusText = R.string.oauth_login_connection;
+        updateAuthStatus();
+        
+        // GET AUTHORIZATION request
+        //Uri uri = Uri.parse(getString(R.string.oauth2_url_endpoint_auth));
+        Uri uri = Uri.parse(mOAuthAuthEndpointText.getText().toString().trim());
+        Uri.Builder uriBuilder = uri.buildUpon();
+        uriBuilder.appendQueryParameter(OAuth2Constants.KEY_RESPONSE_TYPE, getString(R.string.oauth2_response_type));
+        uriBuilder.appendQueryParameter(OAuth2Constants.KEY_REDIRECT_URI, getString(R.string.oauth2_redirect_uri));   
+        uriBuilder.appendQueryParameter(OAuth2Constants.KEY_CLIENT_ID, getString(R.string.oauth2_client_id));
+        uriBuilder.appendQueryParameter(OAuth2Constants.KEY_SCOPE, getString(R.string.oauth2_scope));
+        //uriBuilder.appendQueryParameter(OAuth2Constants.KEY_STATE, whateverwewant);
+        uri = uriBuilder.build();
+        Log_OC.d(TAG, "Starting browser to view " + uri.toString());
+        Intent i = new Intent(Intent.ACTION_VIEW, uri);
+        startActivity(i);
+    }
+
+    
+    /**
+     * Callback method invoked when a RemoteOperation executed by this Activity finishes.
+     * 
+     * Dispatches the operation flow to the right method.
+     */
+    @Override
+    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+
+        if (operation instanceof OwnCloudServerCheckOperation) {
+            onOcServerCheckFinish((OwnCloudServerCheckOperation) operation, result);
+            
+        } else if (operation instanceof OAuth2GetAccessToken) {
+            onGetOAuthAccessTokenFinish((OAuth2GetAccessToken)operation, result);
+                
+        } else if (operation instanceof ExistenceCheckOperation)  {
+            onAuthorizationCheckFinish((ExistenceCheckOperation)operation, result);
+                
+        }
+    }
+    
+
+    /**
+     * Processes the result of the server check performed when the user finishes the enter of the
+     * server URL.
+     * 
+     * @param operation     Server check performed.
+     * @param result        Result of the check.
+     */
+    private void onOcServerCheckFinish(OwnCloudServerCheckOperation operation, RemoteOperationResult result) {
+        /// update status icon and text
+        updateStatusIconAndText(result);
+        updateConnStatus();
+
+        /// save result state
+        mStatusCorrect = result.isSuccess();
+        mIsSslConn = (result.getCode() == ResultCode.OK_SSL);
+        
+        /// very special case (TODO: move to a common place for all the remote operations)
+        if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {
+            mLastSslUntrustedServerResult = result;
+            showDialog(DIALOG_SSL_VALIDATOR); 
+        }
+        
+        /// update the visibility of the 'retry connection' button
+        if (!mStatusCorrect)
+            mRefreshButton.setVisibility(View.VISIBLE);
+        else
+            mRefreshButton.setVisibility(View.INVISIBLE);
+        
+        /// retrieve discovered version and normalize server URL
+        mDiscoveredVersion = operation.getDiscoveredVersion();
+        mHostBaseUrl = mHostUrlInput.getText().toString().trim();
+        if (!mHostBaseUrl.toLowerCase().startsWith("http://") &&
+            !mHostBaseUrl.toLowerCase().startsWith("https://")) {
+            
+            if (mIsSslConn) {
+                mHostBaseUrl = "https://" + mHostBaseUrl;
+            } else {
+                mHostBaseUrl = "http://" + mHostBaseUrl;
+            }
+            
+        }
+        if (mHostBaseUrl.endsWith("/"))
+            mHostBaseUrl = mHostBaseUrl.substring(0, mHostBaseUrl.length() - 1);
+        
+        /// allow or not the user try to access the server
+        mOkButton.setEnabled(mStatusCorrect);
+    }
+
+
+    /**
+     * Chooses the right icon and text to show to the user for the received operation result.
+     * 
+     * @param result    Result of a remote operation performed in this activity
+     */
+    private void updateStatusIconAndText(RemoteOperationResult result) {
+        mStatusText = mStatusIcon = 0;
+
+        switch (result.getCode()) {
+        case OK_SSL:
+            mStatusIcon = android.R.drawable.ic_secure;
+            mStatusText = R.string.auth_secure_connection;
+            break;
+            
+        case OK_NO_SSL:
+        case OK:
+            if (mHostUrlInput.getText().toString().trim().toLowerCase().startsWith("http://") ) {
+                mStatusText = R.string.auth_connection_established;
+                mStatusIcon = R.drawable.ic_ok;
+            } else {
+                mStatusText = R.string.auth_nossl_plain_ok_title;
+                mStatusIcon = android.R.drawable.ic_partial_secure;
+            }
+            break;
+            
+        case SSL_RECOVERABLE_PEER_UNVERIFIED:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_ssl_unverified_server_title;
+            break;
+                
+        case BAD_OC_VERSION:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_bad_oc_version_title;
+            break;
+        case WRONG_CONNECTION:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_wrong_connection_title;
+            break;
+        case TIMEOUT:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_timeout_title;
+            break;
+        case INCORRECT_ADDRESS:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_incorrect_address_title;
+            break;
+            
+        case SSL_ERROR:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_ssl_general_error_title;
+            break;
+            
+        case UNAUTHORIZED:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_unauthorized;
+            break;
+        case HOST_NOT_AVAILABLE:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_unknown_host_title;
+            break;
+        case NO_NETWORK_CONNECTION:
+            mStatusIcon = R.drawable.no_network;
+            mStatusText = R.string.auth_no_net_conn_title;
+            break;
+        case INSTANCE_NOT_CONFIGURED:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_not_configured_title;
+            break;
+        case FILE_NOT_FOUND:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_incorrect_path_title;
+            break;
+        case OAUTH2_ERROR:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_oauth_error;
+            break;
+        case OAUTH2_ERROR_ACCESS_DENIED:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_oauth_error_access_denied;
+            break;
+        case UNHANDLED_HTTP_CODE:
+        case UNKNOWN_ERROR:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_unknown_error_title;
+            break;
+            
+        default:
+            break;
+        }
+    }
+
+
+    /**
+     * Processes the result of the request for and access token send 
+     * to an OAuth authorization server.
+     * 
+     * @param operation     Operation performed requesting the access token.
+     * @param result        Result of the operation.
+     */
+    private void onGetOAuthAccessTokenFinish(OAuth2GetAccessToken operation, RemoteOperationResult result) {
+        try {
+            dismissDialog(DIALOG_OAUTH2_LOGIN_PROGRESS);
+        } catch (IllegalArgumentException e) {
+            // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens
+        }
+
+        String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, true);
+        if (result.isSuccess() && webdav_path != null) {
+            /// be gentle with the user
+            showDialog(DIALOG_LOGIN_PROGRESS);
+            
+            /// time to test the retrieved access token on the ownCloud server
+            mOAuthAccessToken = ((OAuth2GetAccessToken)operation).getResultTokenMap().get(OAuth2Constants.KEY_ACCESS_TOKEN);
+            Log_OC.d(TAG, "Got ACCESS TOKEN: " + mOAuthAccessToken);
+            mAuthCheckOperation = new ExistenceCheckOperation("", this, false);
+            WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this);
+            client.setBearerCredentials(mOAuthAccessToken);
+            mAuthCheckOperation.execute(client, this, mHandler);
+            
+        } else {
+            updateStatusIconAndText(result);
+            updateAuthStatus();
+            Log_OC.d(TAG, "Access failed: " + result.getLogMessage());
+        }
+    }
+
+    
+    /**
+     * Processes the result of the access check performed to try the user credentials.
+     * 
+     * Creates a new account through the AccountManager.
+     * 
+     * @param operation     Access check performed.
+     * @param result        Result of the operation.
+     */
+    private void onAuthorizationCheckFinish(ExistenceCheckOperation operation, RemoteOperationResult result) {
+        try {
+            dismissDialog(DIALOG_LOGIN_PROGRESS);
+        } catch (IllegalArgumentException e) {
+            // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens
+        }
+        
+        if (result.isSuccess()) {
+            Log_OC.d(TAG, "Successful access - time to save the account");
+
+            if (mAction == ACTION_CREATE) {
+                createAccount();
+                
+            } else {
+                updateToken();
+            }
+            
+            finish();
+            
+        } else {
+            updateStatusIconAndText(result);
+            updateAuthStatus();
+            Log_OC.d(TAG, "Access failed: " + result.getLogMessage());
+        }
+    }
+
+    
+    /**
+     * Sets the proper response to get that the Account Authenticator that started this activity saves 
+     * a new authorization token for mAccount.
+     */
+    private void updateToken() {
+        Bundle response = new Bundle();
+        response.putString(AccountManager.KEY_ACCOUNT_NAME, mAccount.name);
+        response.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccount.type);
+        boolean isOAuth = mOAuth2Check.isChecked();
+        if (isOAuth) {
+            response.putString(AccountManager.KEY_AUTHTOKEN, mOAuthAccessToken);
+            // the next line is necessary; by now, notifications are calling directly to the AuthenticatorActivity to update, without AccountManager intervention
+            mAccountMgr.setAuthToken(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, mOAuthAccessToken);
+        } else {
+            response.putString(AccountManager.KEY_AUTHTOKEN, mPasswordInput.getText().toString());
+            mAccountMgr.setPassword(mAccount, mPasswordInput.getText().toString());
+        }
+        setAccountAuthenticatorResult(response);
+    }
+
+
+    /**
+     * Creates a new account through the Account Authenticator that started this activity. 
+     * 
+     * This makes the account permanent.
+     * 
+     * TODO Decide how to name the OAuth accounts
+     */
+    private void createAccount() {
+        /// create and save new ownCloud account
+        boolean isOAuth = mOAuth2Check.isChecked();
+        
+        Uri uri = Uri.parse(mHostBaseUrl);
+        String username = mUsernameInput.getText().toString().trim();
+        if (isOAuth) {
+            username = "OAuth_user" + (new java.util.Random(System.currentTimeMillis())).nextLong();
+        }            
+        String accountName = username + "@" + uri.getHost();
+        if (uri.getPort() >= 0) {
+            accountName += ":" + uri.getPort();
+        }
+        mAccount = new Account(accountName, AccountAuthenticator.ACCOUNT_TYPE);
+        if (isOAuth) {
+            mAccountMgr.addAccountExplicitly(mAccount, "", null);  // with our implementation, the password is never input in the app
+        } else {
+            mAccountMgr.addAccountExplicitly(mAccount, mPasswordInput.getText().toString(), null);
+        }
+
+        /// add the new account as default in preferences, if there is none already
+        Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this);
+        if (defaultAccount == null) {
+            SharedPreferences.Editor editor = PreferenceManager
+                    .getDefaultSharedPreferences(this).edit();
+            editor.putString("select_oc_account", accountName);
+            editor.commit();
+        }
+
+        /// prepare result to return to the Authenticator
+        //  TODO check again what the Authenticator makes with it; probably has the same effect as addAccountExplicitly, but it's not well done
+        final Intent intent = new Intent();       
+        intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE,    AccountAuthenticator.ACCOUNT_TYPE);
+        intent.putExtra(AccountManager.KEY_ACCOUNT_NAME,    mAccount.name);
+        if (!isOAuth)
+            intent.putExtra(AccountManager.KEY_AUTHTOKEN,   AccountAuthenticator.ACCOUNT_TYPE); // TODO check this; not sure it's right; maybe
+        intent.putExtra(AccountManager.KEY_USERDATA,        username);
+        if (isOAuth) {
+            mAccountMgr.setAuthToken(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, mOAuthAccessToken);
+        }
+        /// add user data to the new account; TODO probably can be done in the last parameter addAccountExplicitly, or in KEY_USERDATA
+        mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION,    mDiscoveredVersion.toString());
+        mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL,   mHostBaseUrl);
+        if (isOAuth)
+            mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_OAUTH2, "TRUE");  // TODO this flag should be unnecessary
+    
+        setAccountAuthenticatorResult(intent.getExtras());
+        setResult(RESULT_OK, intent);
+        
+        /// immediately request for the synchronization of the new account
+        Bundle bundle = new Bundle();
+        bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+        ContentResolver.requestSync(mAccount, AccountAuthenticator.AUTHORITY, bundle);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * 
+     * Necessary to update the contents of the SSL Dialog
+     * 
+     * TODO move to some common place for all possible untrusted SSL failures
+     */
+    @Override
+    protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
+        switch (id) {
+        case DIALOG_LOGIN_PROGRESS:
+        case DIALOG_CERT_NOT_SAVED:
+        case DIALOG_OAUTH2_LOGIN_PROGRESS:
+            break;
+        case DIALOG_SSL_VALIDATOR: {
+            ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);
+            break;
+        }
+        default:
+            Log_OC.e(TAG, "Incorrect dialog called with id = " + id);
+        }
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Dialog onCreateDialog(int id) {
+        Dialog dialog = null;
+        switch (id) {
+        case DIALOG_LOGIN_PROGRESS: {
+            /// simple progress dialog
+            ProgressDialog working_dialog = new ProgressDialog(this);
+            working_dialog.setMessage(getResources().getString(R.string.auth_trying_to_login));
+            working_dialog.setIndeterminate(true);
+            working_dialog.setCancelable(true);
+            working_dialog
+                    .setOnCancelListener(new DialogInterface.OnCancelListener() {
+                        @Override
+                        public void onCancel(DialogInterface dialog) {
+                            /// TODO study if this is enough
+                            Log_OC.i(TAG, "Login canceled");
+                            if (mOperationThread != null) {
+                                mOperationThread.interrupt();
+                                finish();
+                            }
+                        }
+                    });
+            dialog = working_dialog;
+            break;
+        }
+        case DIALOG_OAUTH2_LOGIN_PROGRESS: {
+            ProgressDialog working_dialog = new ProgressDialog(this);
+            working_dialog.setMessage(String.format("Getting authorization")); 
+            working_dialog.setIndeterminate(true);
+            working_dialog.setCancelable(true);
+            working_dialog
+            .setOnCancelListener(new DialogInterface.OnCancelListener() {
+                @Override
+                public void onCancel(DialogInterface dialog) {
+                    Log_OC.i(TAG, "Login canceled");
+                    finish();
+                }
+            });
+            dialog = working_dialog;
+            break;
+        }
+        case DIALOG_SSL_VALIDATOR: {
+            /// TODO start to use new dialog interface, at least for this (it is a FragmentDialog already)
+            dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);
+            break;
+        }
+        case DIALOG_CERT_NOT_SAVED: {
+            AlertDialog.Builder builder = new AlertDialog.Builder(this);
+            builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));
+            builder.setCancelable(false);
+            builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        dialog.dismiss();
+                    };
+                });
+            dialog = builder.create();
+            break;
+        }
+        default:
+            Log_OC.e(TAG, "Incorrect dialog called with id = " + id);
+        }
+        return dialog;
+    }
+
+    
+    /**
+     * Starts and activity to open the 'new account' page in the ownCloud web site
+     * 
+     * @param view      'Account register' button
+     */
+    public void onRegisterClick(View view) {
+        Intent register = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_account_register)));
+        setResult(RESULT_CANCELED);
+        startActivity(register);
+    }
+
+    
+    /**
+     * Updates the content and visibility state of the icon and text associated
+     * to the last check on the ownCloud server.
+     */
+    private void updateConnStatus() {
+        ImageView iv = (ImageView) findViewById(R.id.action_indicator);
+        TextView tv = (TextView) findViewById(R.id.status_text);
+
+        if (mStatusIcon == 0 && mStatusText == 0) {
+            iv.setVisibility(View.INVISIBLE);
+            tv.setVisibility(View.INVISIBLE);
+        } else {
+            iv.setImageResource(mStatusIcon);
+            tv.setText(mStatusText);
+            iv.setVisibility(View.VISIBLE);
+            tv.setVisibility(View.VISIBLE);
+        }
+    }
+    
+    
+    /**
+     * Updates the content and visibility state of the icon and text associated
+     * to the interactions with the OAuth authorization server.
+     */
+    private void updateAuthStatus() {
+        if (mStatusIcon == 0 && mStatusText == 0) {
+            mAuthStatusLayout.setVisibility(View.INVISIBLE);
+        } else {
+            mAuthStatusLayout.setText(mStatusText);
+            mAuthStatusLayout.setCompoundDrawablesWithIntrinsicBounds(mStatusIcon, 0, 0, 0);
+            mAuthStatusLayout.setVisibility(View.VISIBLE);
+        }
+    }     
+
+    
+    /**
+     * Called when the refresh button in the input field for ownCloud host is clicked.
+     * 
+     * Performs a new check on the URL in the input field.
+     * 
+     * @param view      Refresh 'button'
+     */
+    public void onRefreshClick(View view) {
+        onFocusChange(mRefreshButton, false);
+    }
+    
+    
+    /**
+     * Called when the eye icon in the password field is clicked.
+     * 
+     * Toggles the visibility of the password in the field. 
+     * 
+     * @param view      'View password' 'button'
+     */
+    public void onViewPasswordClick(View view) {
+        int selectionStart = mPasswordInput.getSelectionStart();
+        int selectionEnd = mPasswordInput.getSelectionEnd();
+        int input_type = mPasswordInput.getInputType();
+        if ((input_type & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
+            input_type = InputType.TYPE_CLASS_TEXT
+                    | InputType.TYPE_TEXT_VARIATION_PASSWORD;
+        } else {
+            input_type = InputType.TYPE_CLASS_TEXT
+                    | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
+        }
+        mPasswordInput.setInputType(input_type);
+        mPasswordInput.setSelection(selectionStart, selectionEnd);
+    }    
+    
+    
+    /**
+     * Called when the checkbox for OAuth authorization is clicked.
+     * 
+     * Hides or shows the input fields for user & password. 
+     * 
+     * @param view      'View password' 'button'
+     */
+    public void onCheckClick(View view) {
+        CheckBox oAuth2Check = (CheckBox)view;      
+        changeViewByOAuth2Check(oAuth2Check.isChecked());
+
+    }
+    
+    /**
+     * Changes the visibility of input elements depending upon the kind of authorization
+     * chosen by the user: basic or OAuth
+     * 
+     * @param checked       'True' when OAuth is selected.
+     */
+    public void changeViewByOAuth2Check(Boolean checked) {
+        
+        if (checked) {
+            mOAuthAuthEndpointText.setVisibility(View.VISIBLE);
+            mOAuthTokenEndpointText.setVisibility(View.VISIBLE);
+            mUsernameInput.setVisibility(View.GONE);
+            mPasswordInput.setVisibility(View.GONE);
+            mViewPasswordButton.setVisibility(View.GONE);
+        } else {
+            mOAuthAuthEndpointText.setVisibility(View.GONE);
+            mOAuthTokenEndpointText.setVisibility(View.GONE);
+            mUsernameInput.setVisibility(View.VISIBLE);
+            mPasswordInput.setVisibility(View.VISIBLE);
+            mViewPasswordButton.setVisibility(View.INVISIBLE);
+        }     
+
+    }    
+    
+    /**
+     * Called from SslValidatorDialog when a new server certificate was correctly saved.
+     */
+    public void onSavedCertificate() {
+        mOperationThread = mOcServerChkOperation.retry(this, mHandler);                
+    }
+
+    /**
+     * Called from SslValidatorDialog when a new server certificate could not be saved 
+     * when the user requested it.
+     */
+    @Override
+    public void onFailedSavingCertificate() {
+        showDialog(DIALOG_CERT_NOT_SAVED);
+    }
+
+}

+ 53 - 0
src/com/owncloud/android/authentication/OAuth2Constants.java

@@ -0,0 +1,53 @@
+/* ownCloud Android client application
+ *   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 version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.authentication;
+
+/** 
+ * Constant values for OAuth 2 protocol.
+ * 
+ * Includes required and optional parameter NAMES used in the 'authorization code' grant type.
+ *  
+ * @author David A. Velasco
+ */
+
+public class OAuth2Constants {
+    
+    /// Parameters to send to the Authorization Endpoint
+    public static final String KEY_RESPONSE_TYPE = "response_type";
+    public static final String KEY_REDIRECT_URI = "redirect_uri";
+    public static final String KEY_CLIENT_ID = "client_id";
+    public static final String KEY_SCOPE = "scope";
+    public static final String KEY_STATE = "state"; 
+    
+    /// Additional parameters to send to the Token Endpoint
+    public static final String KEY_GRANT_TYPE = "grant_type";
+    public static final String KEY_CODE = "code";
+    
+    /// Parameters received in an OK response from the Token Endpoint 
+    public static final String KEY_ACCESS_TOKEN = "access_token";
+    public static final String KEY_TOKEN_TYPE = "token_type";
+    public static final String KEY_EXPIRES_IN = "expires_in";
+    public static final String KEY_REFRESH_TOKEN = "refresh_token";
+    
+    /// Parameters in an ERROR response
+    public static final String KEY_ERROR = "error";
+    public static final String KEY_ERROR_DESCRIPTION = "error_description";
+    public static final String KEY_ERROR_URI = "error_uri";
+    public static final String VALUE_ERROR_ACCESS_DENIED = "access_denied";
+    
+}

+ 0 - 88
src/com/owncloud/android/authenticator/AuthenticationRunnable.java

@@ -1,88 +0,0 @@
-/* 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 version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.authenticator;
-
-import java.net.URL;
-
-import org.apache.commons.httpclient.HttpStatus;
-
-import com.owncloud.android.R;
-import com.owncloud.android.network.OwnCloudClientUtils;
-
-import eu.alefzero.webdav.WebdavClient;
-
-import android.content.Context;
-import android.net.Uri;
-import android.os.Handler;
-
-public class AuthenticationRunnable implements Runnable {
-
-    private OnAuthenticationResultListener mListener;
-    private Handler mHandler;
-    private URL mUrl;
-    private String mUsername;
-    private String mPassword;
-    private Context mContext;
-
-    public AuthenticationRunnable(URL url, String username, String password, Context context) {
-        mListener = null;
-        mUrl = url;
-        mUsername = username;
-        mPassword = password;
-        mContext = context;
-    }
-
-    public void setOnAuthenticationResultListener(
-            OnAuthenticationResultListener listener, Handler handler) {
-        mListener = listener;
-        mHandler = handler;
-    }
-
-    @Override
-    public void run() {
-        Uri uri;
-        uri = Uri.parse(mUrl.toString());
-        WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(uri, mUsername, mPassword, mContext);
-        int login_result = wdc.tryToLogin();
-        switch (login_result) {
-        case HttpStatus.SC_OK:
-            postResult(true, uri.toString());
-            break;
-        case HttpStatus.SC_UNAUTHORIZED:
-            postResult(false, mContext.getString(R.string.auth_unauthorized));
-            break;
-        case HttpStatus.SC_NOT_FOUND:
-            postResult(false, mContext.getString(R.string.auth_not_found));
-            break;
-        default:
-            postResult(false, String.format(mContext.getString(R.string.auth_internal), login_result));
-        }
-    }
-
-    private void postResult(final boolean success, final String message) {
-        if (mHandler != null && mListener != null) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mListener.onAuthenticationResult(success, message);
-                }
-            });
-        }
-    }
-}

+ 0 - 25
src/com/owncloud/android/authenticator/OnAuthenticationResultListener.java

@@ -1,25 +0,0 @@
-/* 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 version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.authenticator;
-
-public interface OnAuthenticationResultListener {
-
-    public void onAuthenticationResult(boolean success, String message);
-
-}

+ 0 - 29
src/com/owncloud/android/authenticator/OnConnectCheckListener.java

@@ -1,29 +0,0 @@
-/* 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 version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.authenticator;
-
-public interface OnConnectCheckListener {
-
-    enum ResultType {
-        OK_SSL, OK_NO_SSL, SSL_INIT_ERROR, HOST_NOT_AVAILABLE, TIMEOUT, NO_NETWORK_CONNECTION, INCORRECT_ADDRESS, INSTANCE_NOT_CONFIGURED, FILE_NOT_FOUND, UNKNOWN_ERROR, WRONG_CONNECTION,  SSL_UNVERIFIED_SERVER, BAD_OC_VERSION
-    }
-
-    public void onConnectionCheckResult(ResultType type);
-
-}

+ 0 - 1
src/com/owncloud/android/datamodel/FileDataStorageManager.java

@@ -40,7 +40,6 @@ import android.content.OperationApplicationException;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.RemoteException;
-import android.util.Log;
 
 public class FileDataStorageManager implements DataStorageManager {
 

+ 0 - 1
src/com/owncloud/android/db/DbHandler.java

@@ -24,7 +24,6 @@ import android.content.Context;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
-import android.util.Log;
 
 /**
  * Custom database helper for ownCloud

+ 0 - 1
src/com/owncloud/android/extensions/ExtensionsAvailableDialog.java

@@ -23,7 +23,6 @@ import com.owncloud.android.R;
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.v4.app.DialogFragment;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;

+ 0 - 1
src/com/owncloud/android/extensions/ExtensionsListActivity.java

@@ -35,7 +35,6 @@ import android.R;
 import android.app.ListActivity;
 import android.os.Bundle;
 import android.os.Handler;
-import android.util.Log;
 import android.widget.SimpleAdapter;
 
 public class ExtensionsListActivity extends ListActivity {

+ 0 - 1
src/com/owncloud/android/files/BootupBroadcastReceiver.java

@@ -24,7 +24,6 @@ import com.owncloud.android.files.services.FileObserverService;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.util.Log;
 
 public class BootupBroadcastReceiver extends BroadcastReceiver {
 

+ 5 - 4
src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java

@@ -20,6 +20,11 @@ package com.owncloud.android.files;
 
 import java.io.File;
 
+import com.owncloud.android.AccountUtils;
+import com.owncloud.android.authentication.AccountAuthenticator;
+import com.owncloud.android.db.DbHandler;
+import com.owncloud.android.files.services.FileUploader;
+
 import android.accounts.Account;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -32,11 +37,7 @@ import android.preference.PreferenceManager;
 import android.provider.MediaStore.Images.Media;
 import android.webkit.MimeTypeMap;
 
-import com.owncloud.android.AccountUtils;
 import com.owncloud.android.Log_OC;
-import com.owncloud.android.authenticator.AccountAuthenticator;
-import com.owncloud.android.db.DbHandler;
-import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.utils.FileStorageUtils;
 
 public class InstantUploadBroadcastReceiver extends BroadcastReceiver {

+ 1 - 5
src/com/owncloud/android/files/OwnCloudFileObserver.java

@@ -23,19 +23,16 @@ import java.io.File;
 import com.owncloud.android.Log_OC;
 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;
 import android.content.Intent;
 import android.os.FileObserver;
-import android.util.Log;
 
 public class OwnCloudFileObserver extends FileObserver {
 
@@ -78,7 +75,6 @@ public class OwnCloudFileObserver extends FileObserver {
                          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; 
@@ -89,7 +85,7 @@ public class OwnCloudFileObserver extends FileObserver {
                                                                     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);

+ 51 - 25
src/com/owncloud/android/files/services/FileDownloader.java

@@ -19,6 +19,7 @@
 package com.owncloud.android.files.services;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.AbstractList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -27,6 +28,7 @@ import java.util.Vector;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import com.owncloud.android.authentication.AuthenticatorActivity;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import eu.alefzero.webdav.OnDatatransferProgressListener;
@@ -34,12 +36,14 @@ import eu.alefzero.webdav.OnDatatransferProgressListener;
 import com.owncloud.android.network.OwnCloudClientUtils;
 import com.owncloud.android.operations.DownloadFileOperation;
 import com.owncloud.android.operations.RemoteOperationResult;
+import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.ui.activity.FileDetailActivity;
 import com.owncloud.android.ui.fragment.FileDetailFragment;
 import com.owncloud.android.ui.preview.PreviewImageActivity;
 import com.owncloud.android.ui.preview.PreviewImageFragment;
 
 import android.accounts.Account;
+import android.accounts.AccountsException;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -113,7 +117,6 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         mBinder = new FileDownloaderBinder();
     }
 
-    
     /**
      * Entry point to add one or several files to the queue of downloads.
      * 
@@ -256,7 +259,6 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         }
         
         
-        
         /**
          * Removes a listener interested in the progress of the download for a concrete file.
          * 
@@ -321,7 +323,6 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         }
     }
     
-    
 
     /**
      * Core download method: requests a file to download and stores it.
@@ -338,21 +339,28 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
             
             notifyDownloadStart(mCurrentDownload);
 
-            /// prepare client object to send the request to the ownCloud server
-            if (mDownloadClient == null || !mLastAccount.equals(mCurrentDownload.getAccount())) {
-                mLastAccount = mCurrentDownload.getAccount();
-                mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());
-                mDownloadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());
-            }
-
-            /// perform the download
             RemoteOperationResult downloadResult = null;
             try {
+                /// prepare client object to send the request to the ownCloud server
+                if (mDownloadClient == null || !mLastAccount.equals(mCurrentDownload.getAccount())) {
+                    mLastAccount = mCurrentDownload.getAccount();
+                    mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());
+                    mDownloadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());
+                }
+
+                /// perform the download
                 downloadResult = mCurrentDownload.execute(mDownloadClient);
                 if (downloadResult.isSuccess()) {
                     saveDownloadedFile();
                 }
             
+            } catch (AccountsException e) {
+                Log_OC.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
+                downloadResult = new RemoteOperationResult(e);
+            } catch (IOException e) {
+                Log_OC.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
+                downloadResult = new RemoteOperationResult(e);
+                
             } finally {
                 synchronized(mPendingDownloads) {
                     mPendingDownloads.remove(downloadKey);
@@ -455,23 +463,41 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
             int contentId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_content : R.string.downloader_download_failed_content;
             Notification finalNotification = new Notification(R.drawable.icon, getString(tickerId), System.currentTimeMillis());
             finalNotification.flags |= Notification.FLAG_AUTO_CANCEL;
-            Intent showDetailsIntent = null;
-            if (downloadResult.isSuccess()) {
-                if (PreviewImageFragment.canBePreviewed(download.getFile())) {
-                    showDetailsIntent = new Intent(this, PreviewImageActivity.class);
-                } else {
-                    showDetailsIntent = new Intent(this, FileDetailActivity.class);
-                }
-                showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, download.getFile());
-                showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, download.getAccount());
-                showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            boolean needsToUpdateCredentials = (downloadResult.getCode() == ResultCode.UNAUTHORIZED);
+            if (needsToUpdateCredentials) {
+                // let the user update credentials with one click
+                Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
+                updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, download.getAccount());
+                updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);
+                updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);
+                finalNotification.contentIntent = PendingIntent.getActivity(this, (int)System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT);
+                finalNotification.setLatestEventInfo(   getApplicationContext(), 
+                                                        getString(tickerId), 
+                                                        String.format(getString(contentId), new File(download.getSavePath()).getName()),
+                                                        finalNotification.contentIntent);
+                mDownloadClient = null;   // grant that future retries on the same account will get the fresh credentials
                 
             } else {
-                // TODO put something smart in showDetailsIntent
-                showDetailsIntent = new Intent();
+                Intent showDetailsIntent = null;
+                if (downloadResult.isSuccess()) {
+                    if (PreviewImageFragment.canBePreviewed(download.getFile())) {
+                        showDetailsIntent = new Intent(this, PreviewImageActivity.class);
+                    } else {
+                        showDetailsIntent = new Intent(this, FileDetailActivity.class);
+                    }
+                    showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, download.getFile());
+                    showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, download.getAccount());
+                    showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                    
+                } else {
+                    // TODO put something smart in showDetailsIntent
+                    showDetailsIntent = new Intent();
+                }
+                finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0);
+                finalNotification.setLatestEventInfo(getApplicationContext(), getString(tickerId), String.format(getString(contentId), new File(download.getSavePath()).getName()), finalNotification.contentIntent);
             }
-            finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0);
-            finalNotification.setLatestEventInfo(getApplicationContext(), getString(tickerId), String.format(getString(contentId), new File(download.getSavePath()).getName()), finalNotification.contentIntent);
             mNotificationManager.notify(tickerId, finalNotification);
         }
     }

+ 0 - 1
src/com/owncloud/android/files/services/FileObserverService.java

@@ -40,7 +40,6 @@ import android.content.IntentFilter;
 import android.database.Cursor;
 import android.os.Binder;
 import android.os.IBinder;
-import android.util.Log;
 
 public class FileObserverService extends Service {
 

+ 0 - 55
src/com/owncloud/android/files/services/FileOperation.java

@@ -1,55 +0,0 @@
-/* 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 version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-package com.owncloud.android.files.services;
-
-import java.io.File;
-
-import com.owncloud.android.AccountUtils;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.network.OwnCloudClientUtils;
-
-import android.accounts.Account;
-import android.content.Context;
-import eu.alefzero.webdav.WebdavClient;
-
-public class FileOperation {
-
-    Context mContext;
-    
-    public FileOperation(Context contex){
-        this.mContext = contex;
-    }
-    
-    /**
-     * Deletes a file from ownCloud - locally and remote.
-     * @param file The file to delete
-     * @return True on success, otherwise false
-     */
-    public boolean delete(OCFile file){
-        
-        Account account = AccountUtils.getCurrentOwnCloudAccount(mContext);
-        WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(account, mContext);
-        if(client.deleteFile(file.getRemotePath())){
-            File localFile = new File(file.getStoragePath());
-            return localFile.delete();
-        }
-        
-        return false;
-    }
-    
-}

+ 67 - 35
src/com/owncloud/android/files/services/FileUploader.java

@@ -19,6 +19,7 @@
 package com.owncloud.android.files.services;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.AbstractList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -31,8 +32,29 @@ import org.apache.http.HttpStatus;
 import org.apache.jackrabbit.webdav.MultiStatus;
 import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
 
+import com.owncloud.android.authentication.AccountAuthenticator;
+import com.owncloud.android.authentication.AuthenticatorActivity;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+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;
+import com.owncloud.android.ui.activity.FileDetailActivity;
+import com.owncloud.android.ui.fragment.FileDetailFragment;
+import com.owncloud.android.utils.OwnCloudVersion;
+
+import eu.alefzero.webdav.OnDatatransferProgressListener;
+import eu.alefzero.webdav.WebdavEntry;
+import eu.alefzero.webdav.WebdavUtils;
+
+import com.owncloud.android.network.OwnCloudClientUtils;
+
 import android.accounts.Account;
 import android.accounts.AccountManager;
+import android.accounts.AccountsException;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -47,32 +69,17 @@ import android.os.Message;
 import android.os.Process;
 import android.webkit.MimeTypeMap;
 import android.widget.RemoteViews;
-import android.widget.Toast;
 
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
-import com.owncloud.android.authenticator.AccountAuthenticator;
-import com.owncloud.android.datamodel.FileDataStorageManager;
-import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.db.DbHandler;
-import com.owncloud.android.network.OwnCloudClientUtils;
-import com.owncloud.android.operations.ChunkedUploadFileOperation;
-import com.owncloud.android.operations.RemoteOperationResult;
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
-import com.owncloud.android.operations.UploadFileOperation;
 import com.owncloud.android.ui.activity.FailedUploadActivity;
-import com.owncloud.android.ui.activity.FileDetailActivity;
 import com.owncloud.android.ui.activity.InstantUploadActivity;
-import com.owncloud.android.ui.fragment.FileDetailFragment;
 import com.owncloud.android.ui.preview.PreviewImageActivity;
 import com.owncloud.android.ui.preview.PreviewImageFragment;
 import com.owncloud.android.utils.FileStorageUtils;
-import com.owncloud.android.utils.OwnCloudVersion;
 
-import eu.alefzero.webdav.OnDatatransferProgressListener;
 import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavEntry;
-import eu.alefzero.webdav.WebdavUtils;
 
 public class FileUploader extends Service implements OnDatatransferProgressListener {
 
@@ -490,37 +497,48 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
 
             notifyUploadStart(mCurrentUpload);
 
-            // / 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(FileStorageUtils.getInstantUploadFilePath(this, ""));
-                // 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 {
+                /// 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()) {
+                    RemoteOperation operation = new CreateFolderOperation(  FileStorageUtils.getInstantUploadFilePath(this, ""), 
+                                                                            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
                 uploadResult = mCurrentUpload.execute(mUploadClient);
                 if (uploadResult.isSuccess()) {
                     saveUploadedFile();
                 }
-
+                
+            } catch (AccountsException e) {
+                Log_OC.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
+                uploadResult = new RemoteOperationResult(e);
+                
+            } catch (IOException e) {
+                Log_OC.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
+                uploadResult = new RemoteOperationResult(e);
+                
             } finally {
                 synchronized (mPendingUploads) {
                     mPendingUploads.remove(uploadKey);
                     Log_OC.i(TAG, "Remove CurrentUploadItem from pending upload Item Map.");
                 }
             }
-
-            // notify result
+            
+            /// notify result
+            
             notifyUploadResult(uploadResult, mCurrentUpload);
             sendFinalBroadcast(mCurrentUpload, uploadResult);
 
@@ -775,7 +793,21 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
             Notification finalNotification = new Notification(R.drawable.icon,
                     getString(R.string.uploader_upload_failed_ticker), System.currentTimeMillis());
             finalNotification.flags |= Notification.FLAG_AUTO_CANCEL;
-
+            if (uploadResult.getCode() == ResultCode.UNAUTHORIZED) {
+                // let the user update credentials with one click
+                Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
+                updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, upload.getAccount());
+                updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);
+                updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);
+                finalNotification.contentIntent = PendingIntent.getActivity(this, (int)System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT);
+                mUploadClient = null;   // grant that future retries on the same account will get the fresh credentials
+            } else {
+                // TODO put something smart in the contentIntent below
+                finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);
+            }
+            
             String content = null;
             if (uploadResult.getCode() == ResultCode.LOCAL_STORAGE_FULL
                     || uploadResult.getCode() == ResultCode.LOCAL_STORAGE_NOT_COPIED) {

+ 0 - 1
src/com/owncloud/android/location/LocationServiceLauncherReciever.java

@@ -26,7 +26,6 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.preference.PreferenceManager;
-import android.util.Log;
 
 public class LocationServiceLauncherReciever extends BroadcastReceiver {
 

+ 0 - 1
src/com/owncloud/android/location/LocationUpdateService.java

@@ -27,7 +27,6 @@ import android.location.LocationManager;
 import android.location.LocationProvider;
 import android.os.Bundle;
 import android.preference.PreferenceManager;
-import android.util.Log;
 import android.widget.Toast;
 
 import com.owncloud.android.Log_OC;

+ 0 - 2
src/com/owncloud/android/network/AdvancedSslSocketFactory.java

@@ -41,8 +41,6 @@ import org.apache.http.conn.ssl.X509HostnameVerifier;
 
 import com.owncloud.android.Log_OC;
 
-import android.util.Log;
-
 /**
  * AdvancedSSLProtocolSocketFactory allows to create SSL {@link Socket}s with 
  * a custom SSLContext and an optional Hostname Verifier.

+ 0 - 2
src/com/owncloud/android/network/AdvancedX509TrustManager.java

@@ -33,8 +33,6 @@ import javax.net.ssl.X509TrustManager;
 
 import com.owncloud.android.Log_OC;
 
-import android.util.Log;
-
 /**
  * @author David A. Velasco
  */

+ 268 - 0
src/com/owncloud/android/network/BearerAuthScheme.java

@@ -0,0 +1,268 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012  ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.network;
+
+import java.util.Map;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.auth.AuthChallengeParser;
+import org.apache.commons.httpclient.auth.AuthScheme;
+import org.apache.commons.httpclient.auth.AuthenticationException;
+import org.apache.commons.httpclient.auth.InvalidCredentialsException;
+import org.apache.commons.httpclient.auth.MalformedChallengeException;
+
+import com.owncloud.android.Log_OC;
+
+/**
+ * Bearer authentication scheme as defined in RFC 6750.
+ * 
+ * @author David A. Velasco
+ */
+
+public class BearerAuthScheme implements AuthScheme /*extends RFC2617Scheme*/ {
+    
+    private static final String TAG = BearerAuthScheme.class.getSimpleName();
+
+    public static final String AUTH_POLICY = "Bearer";
+    
+    /** Whether the bearer authentication process is complete */
+    private boolean mComplete;
+    
+    /** Authentication parameter map */
+    private Map mParams = null;
+    
+    
+    /**
+     * Default constructor for the bearer authentication scheme.
+     */
+    public BearerAuthScheme() {
+        mComplete = false;
+    }
+
+    /**
+     * Constructor for the basic authentication scheme.
+     * 
+     * @param   challenge                       Authentication challenge
+     * 
+     * @throws  MalformedChallengeException     Thrown if the authentication challenge is malformed
+     * 
+     * @deprecated Use parameterless constructor and {@link AuthScheme#processChallenge(String)} method
+     */
+    public BearerAuthScheme(final String challenge) throws MalformedChallengeException {
+        processChallenge(challenge);
+        mComplete = true;
+    }
+
+    /**
+     * Returns textual designation of the bearer authentication scheme.
+     * 
+     * @return "Bearer"
+     */
+    public String getSchemeName() {
+        return "bearer";
+    }
+
+    /**
+     * Processes the Bearer challenge.
+     *  
+     * @param   challenge                   The challenge string
+     * 
+     * @throws MalformedChallengeException  Thrown if the authentication challenge is malformed
+     */
+    public void processChallenge(String challenge) throws MalformedChallengeException {
+        String s = AuthChallengeParser.extractScheme(challenge);
+        if (!s.equalsIgnoreCase(getSchemeName())) {
+            throw new MalformedChallengeException(
+              "Invalid " + getSchemeName() + " challenge: " + challenge); 
+        }
+        mParams = AuthChallengeParser.extractParams(challenge);
+        mComplete = true;
+    }
+
+    /**
+     * Tests if the Bearer authentication process has been completed.
+     * 
+     * @return 'true' if Bearer authorization has been processed, 'false' otherwise.
+     */
+    public boolean isComplete() {
+        return this.mComplete;
+    }
+
+    /**
+     * Produces bearer authorization string for the given set of 
+     * {@link Credentials}.
+     * 
+     * @param   credentials                     The set of credentials to be used for authentication
+     * @param   method                          Method name is ignored by the bearer authentication scheme
+     * @param   uri                             URI is ignored by the bearer authentication scheme
+     * @throws  InvalidCredentialsException     If authentication credentials are not valid or not applicable 
+     *                                          for this authentication scheme
+     * @throws  AuthenticationException         If authorization string cannot be generated due to an authentication failure
+     * @return  A bearer authorization string
+     * 
+     * @deprecated Use {@link #authenticate(Credentials, HttpMethod)}
+     */
+    public String authenticate(Credentials credentials, String method, String uri) throws AuthenticationException {
+        Log_OC.d(TAG, "enter BearerScheme.authenticate(Credentials, String, String)");
+
+        BearerCredentials bearer = null;
+        try {
+            bearer = (BearerCredentials) credentials;
+        } catch (ClassCastException e) {
+            throw new InvalidCredentialsException(
+             "Credentials cannot be used for bearer authentication: " 
+              + credentials.getClass().getName());
+        }
+        return BearerAuthScheme.authenticate(bearer);
+    }
+
+    
+    /**
+     * Returns 'false'. Bearer authentication scheme is request based.
+     * 
+     * @return 'false'.
+     */
+    public boolean isConnectionBased() {
+        return false;    
+    }
+
+    /**
+     * Produces bearer authorization string for the given set of {@link Credentials}.
+     * 
+     * @param   credentials                     The set of credentials to be used for authentication
+     * @param   method                          The method being authenticated
+     * @throws  InvalidCredentialsException     If authentication credentials are not valid or not applicable for this authentication 
+     *                                          scheme.
+     * @throws AuthenticationException         If authorization string cannot be generated due to an authentication failure.
+     * 
+     * @return a basic authorization string
+     */
+    public String authenticate(Credentials credentials, HttpMethod method) throws AuthenticationException {
+        Log_OC.d(TAG, "enter BearerScheme.authenticate(Credentials, HttpMethod)");
+
+        if (method == null) {
+            throw new IllegalArgumentException("Method may not be null");
+        }
+        BearerCredentials bearer = null;
+        try {
+            bearer = (BearerCredentials) credentials;
+        } catch (ClassCastException e) {
+            throw new InvalidCredentialsException(
+                    "Credentials cannot be used for bearer authentication: " 
+                    + credentials.getClass().getName());
+        }
+        return BearerAuthScheme.authenticate(
+            bearer, 
+            method.getParams().getCredentialCharset());
+    }
+    
+    /**
+     * @deprecated Use {@link #authenticate(BearerCredentials, String)}
+     * 
+     * Returns a bearer Authorization header value for the given 
+     * {@link BearerCredentials}.
+     * 
+     * @param   credentials     The credentials to encode.
+     * 
+     * @return                  A bearer authorization string
+     */
+    public static String authenticate(BearerCredentials credentials) {
+        return authenticate(credentials, "ISO-8859-1");
+    }
+
+    /**
+     * Returns a bearer Authorization header value for the given 
+     * {@link BearerCredentials} and charset.
+     * 
+     * @param   credentials         The credentials to encode.
+     * @param   charset             The charset to use for encoding the credentials
+     * 
+     * @return                      A bearer authorization string
+     * 
+     * @since 3.0
+     */
+    public static String authenticate(BearerCredentials credentials, String charset) {
+        Log_OC.d(TAG, "enter BearerAuthScheme.authenticate(BearerCredentials, String)");
+
+        if (credentials == null) {
+            throw new IllegalArgumentException("Credentials may not be null"); 
+        }
+        if (charset == null || charset.length() == 0) {
+            throw new IllegalArgumentException("charset may not be null or empty");
+        }
+        StringBuffer buffer = new StringBuffer();
+        buffer.append(credentials.getAccessToken());
+        
+        //return "Bearer " + EncodingUtil.getAsciiString(EncodingUtil.getBytes(buffer.toString(), charset));
+        return "Bearer " + buffer.toString();
+    }
+
+    /**
+     * Returns a String identifying the authentication challenge.  This is
+     * used, in combination with the host and port to determine if
+     * authorization has already been attempted or not.  Schemes which
+     * require multiple requests to complete the authentication should
+     * return a different value for each stage in the request.
+     * 
+     * Additionally, the ID should take into account any changes to the
+     * authentication challenge and return a different value when appropriate.
+     * For example when the realm changes in basic authentication it should be
+     * considered a different authentication attempt and a different value should
+     * be returned.
+     * 
+     * This method simply returns the realm for the challenge.
+     * 
+     * @return String       a String identifying the authentication challenge.
+     * 
+     * @deprecated no longer used
+     */
+    @Override
+    public String getID() {
+        return getRealm();
+    }
+
+    /**
+     * Returns authentication parameter with the given name, if available.
+     * 
+     * @param   name    The name of the parameter to be returned
+     * 
+     * @return          The parameter with the given name
+     */
+    @Override
+    public String getParameter(String name) {
+        if (name == null) {
+            throw new IllegalArgumentException("Parameter name may not be null"); 
+        }
+        if (mParams == null) {
+            return null;
+        }
+        return (String) mParams.get(name.toLowerCase());
+    }
+
+    /**
+     * Returns authentication realm. The realm may not be null.
+     * 
+     * @return  The authentication realm
+     */
+    @Override
+    public String getRealm() {
+        return getParameter("realm");
+    }
+    
+}

+ 97 - 0
src/com/owncloud/android/network/BearerCredentials.java

@@ -0,0 +1,97 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012  ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.network;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.util.LangUtils;
+
+/**
+ * Bearer token {@link Credentials}
+ *
+ * @author David A. Velasco
+ */
+public class BearerCredentials implements Credentials {
+
+    
+    private String mAccessToken;
+    
+    
+    /**
+     * The constructor with the bearer token
+     *
+     * @param token     The bearer token
+     */
+    public BearerCredentials(String token) {
+        /*if (token == null) {
+            throw new IllegalArgumentException("Bearer token may not be null");            
+        }*/
+        mAccessToken = (token == null) ? "" : token;
+    }
+
+
+    /**
+     * Returns the access token
+     *
+     * @return      The access token
+     */
+    public String getAccessToken() {
+        return mAccessToken;
+    }
+
+
+    /**
+     * Get this object string.
+     *
+     * @return  The access token
+     */
+    public String toString() {
+        return mAccessToken;
+    }
+
+    /**
+     * Does a hash of the access token.
+     *
+     * @return The hash code of the access token
+     */
+    public int hashCode() {
+        int hash = LangUtils.HASH_SEED;
+        hash = LangUtils.hashCode(hash, mAccessToken);
+        return hash;
+    }
+
+    /**
+     * These credentials are assumed equal if accessToken is the same.
+     *
+     * @param   o   The other object to compare with.
+     *
+     * @return      'True' if the object is equivalent.
+     */
+    public boolean equals(Object o) {
+        if (o == null) return false;
+        if (this == o) return true;
+        if (this.getClass().equals(o.getClass())) {
+            BearerCredentials that = (BearerCredentials) o;
+            if (LangUtils.equals(mAccessToken, that.mAccessToken)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
+

+ 52 - 31
src/com/owncloud/android/network/OwnCloudClientUtils.java

@@ -37,19 +37,24 @@ import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
 import org.apache.http.conn.ssl.X509HostnameVerifier;
 
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.authentication.AccountAuthenticator;
 import com.owncloud.android.Log_OC;
 
 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.util.Log;
+import android.os.Bundle;
 
 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;
@@ -70,46 +75,61 @@ public class OwnCloudClientUtils {
     /**
      * 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_OC.d(TAG, "Creating WebdavClient associated to " + account.name);
+    public static WebdavClient createOwnCloudClient (Account account, Context appContext) throws OperationCanceledException, AuthenticatorException, IOException {
+        //Log_OC.d(TAG, "Creating WebdavClient associated to " + account.name);
        
-        Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(context, account));
-        WebdavClient client = createOwnCloudClient(uri, context);
+        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
         
-        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);
-        
-        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_OC.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.
      * 
@@ -118,7 +138,7 @@ public class OwnCloudClientUtils {
      * @return          A WebdavClient object ready to be used
      */
     public static WebdavClient createOwnCloudClient(Uri uri, Context context) {
-        Log_OC.d(TAG, "Creating WebdavClient for " + uri);
+        //Log_OC.d(TAG, "Creating WebdavClient for " + uri);
         
         //allowSelfsignedCertificates(true);
         try {
@@ -244,4 +264,5 @@ public class OwnCloudClientUtils {
         return mConnManager;
     }
 
+
 }

+ 0 - 1
src/com/owncloud/android/operations/ChunkedUploadFileOperation.java

@@ -32,7 +32,6 @@ import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.network.ProgressiveDataTransferer;
 
 import android.accounts.Account;
-import android.util.Log;
 
 import eu.alefzero.webdav.ChunkFromFileChannelRequestEntity;
 import eu.alefzero.webdav.WebdavClient;

+ 94 - 0
src/com/owncloud/android/operations/CreateFolderOperation.java

@@ -0,0 +1,94 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.operations;
+
+import org.apache.jackrabbit.webdav.client.methods.MkColMethod;
+
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.datamodel.DataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+
+import eu.alefzero.webdav.WebdavClient;
+import eu.alefzero.webdav.WebdavUtils;
+
+/**
+ * Remote operation performing the creation of a new folder in the ownCloud server.
+ * 
+ * @author David A. Velasco 
+ */
+public class CreateFolderOperation extends RemoteOperation {
+    
+    private static final String TAG = CreateFolderOperation.class.getSimpleName();
+
+    private static final int READ_TIMEOUT = 10000;
+    private static final int CONNECTION_TIMEOUT = 5000;
+    
+    protected String mRemotePath;
+    protected long mParentDirId;
+    protected DataStorageManager mStorageManager;
+    
+    /**
+     * Constructor
+     * 
+     * @param remoetPath            Full path to the new directory to create in the remote server.
+     * @param parentDirId           Local database id for the parent folder.
+     * @param storageManager        Reference to the local database corresponding to the account where the file is contained. 
+     */
+    public CreateFolderOperation(String remotePath, long parentDirId, DataStorageManager storageManager) {
+        mRemotePath = remotePath;
+        mParentDirId = parentDirId;
+        mStorageManager = storageManager;
+    }
+    
+    
+    /**
+     * Performs the remove operation
+     * 
+     * @param   client      Client object to communicate with the remote ownCloud server.
+     */
+    @Override
+    protected RemoteOperationResult run(WebdavClient client) {
+        RemoteOperationResult result = null;
+        MkColMethod mkcol = null;
+        try {
+            mkcol = new MkColMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath));
+            int status =  client.executeMethod(mkcol, READ_TIMEOUT, CONNECTION_TIMEOUT);
+            if (mkcol.succeeded()) {
+                // Save new directory in local database
+                OCFile newDir = new OCFile(mRemotePath);
+                newDir.setMimetype("DIR");
+                newDir.setParentId(mParentDirId);
+                mStorageManager.saveFile(newDir);
+            }
+
+            result = new RemoteOperationResult(mkcol.succeeded(), status);
+            Log_OC.d(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage());
+            client.exhaustResponse(mkcol.getResponseBodyAsStream());
+                
+        } catch (Exception e) {
+            result = new RemoteOperationResult(e);
+            Log_OC.e(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage(), e);
+            
+        } finally {
+            if (mkcol != null)
+                mkcol.releaseConnection();
+        }
+        return result;
+    }
+    
+}

+ 0 - 1
src/com/owncloud/android/operations/DownloadFileOperation.java

@@ -42,7 +42,6 @@ import eu.alefzero.webdav.OnDatatransferProgressListener;
 import eu.alefzero.webdav.WebdavClient;
 import eu.alefzero.webdav.WebdavUtils;
 import android.accounts.Account;
-import android.util.Log;
 import android.webkit.MimeTypeMap;
 
 /**

+ 94 - 0
src/com/owncloud/android/operations/ExistenceCheckOperation.java

@@ -0,0 +1,94 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.operations;
+
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.methods.HeadMethod;
+
+import com.owncloud.android.Log_OC;
+
+import eu.alefzero.webdav.WebdavClient;
+import android.content.Context;
+import android.net.ConnectivityManager;
+
+/**
+ * Operation to check the existence or absence of a path in a remote server.
+ * 
+ * @author David A. Velasco
+ */
+public class ExistenceCheckOperation extends RemoteOperation {
+    
+    /** Maximum time to wait for a response from the server in MILLISECONDs.  */
+    public static final int TIMEOUT = 10000;
+    
+    private static final String TAG = ExistenceCheckOperation.class.getSimpleName();
+    
+    private String mPath;
+    private Context mContext;
+    private boolean mSuccessIfAbsent;
+
+    
+    /**
+     * Full constructor. Success of the operation will depend upon the value of successIfAbsent.
+     * 
+     * @param path              Path to append to the URL owned by the client instance.
+     * @param context           Android application context.
+     * @param successIfAbsent   When 'true', the operation finishes in success if the path does NOT exist in the remote server (HTTP 404).
+     */
+    public ExistenceCheckOperation(String path, Context context, boolean successIfAbsent) {
+        mPath = (path != null) ? path : "";
+        mContext = context;
+        mSuccessIfAbsent = successIfAbsent;
+    }
+    
+
+	@Override
+	protected RemoteOperationResult run(WebdavClient client) {
+        if (!isOnline()) {
+            return new RemoteOperationResult(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION);
+        }
+        RemoteOperationResult result = null;
+        HeadMethod head = null;
+        try {
+            head = new HeadMethod(client.getBaseUri() + mPath);
+            int status = client.executeMethod(head, TIMEOUT, TIMEOUT);
+            client.exhaustResponse(head.getResponseBodyAsStream());
+            boolean success = (status == HttpStatus.SC_OK && !mSuccessIfAbsent) || (status == HttpStatus.SC_NOT_FOUND && mSuccessIfAbsent);
+            result = new RemoteOperationResult(success, status);
+            Log_OC.d(TAG, "Existence check for " + client.getBaseUri() + mPath + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + "finished with HTTP status " + status + (!success?"(FAIL)":""));
+            
+        } catch (Exception e) {
+            result = new RemoteOperationResult(e);
+            Log_OC.e(TAG, "Existence check for " + client.getBaseUri() + mPath + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + ": " + result.getLogMessage(), result.getException());
+            
+        } finally {
+            if (head != null)
+                head.releaseConnection();
+        }
+        return result;
+	}
+
+    private boolean isOnline() {
+        ConnectivityManager cm = (ConnectivityManager) mContext
+                .getSystemService(Context.CONNECTIVITY_SERVICE);
+        return cm != null && cm.getActiveNetworkInfo() != null
+                && cm.getActiveNetworkInfo().isConnectedOrConnecting();
+    }
+
+
+}

+ 174 - 0
src/com/owncloud/android/operations/OAuth2GetAccessToken.java

@@ -0,0 +1,174 @@
+package com.owncloud.android.operations;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.NameValuePair;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.authentication.OAuth2Constants;
+import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
+
+import eu.alefzero.webdav.WebdavClient;
+
+public class OAuth2GetAccessToken extends RemoteOperation {
+    
+    private static final String TAG = OAuth2GetAccessToken.class.getSimpleName();
+    
+    private String mClientId;
+    private String mRedirectUri;
+    private String mGrantType;
+    
+    private String mOAuth2AuthorizationResponse;
+    private Map<String, String> mOAuth2ParsedAuthorizationResponse;
+    private Map<String, String> mResultTokenMap;
+
+    
+    public OAuth2GetAccessToken(String clientId, String redirectUri, String grantType, String oAuth2AuthorizationResponse) {
+        mClientId = clientId;
+        mRedirectUri = redirectUri;
+        mGrantType = grantType;
+        mOAuth2AuthorizationResponse = oAuth2AuthorizationResponse;
+        mOAuth2ParsedAuthorizationResponse = new HashMap<String, String>();
+        mResultTokenMap = null;
+    }
+    
+    
+    public Map<String, String> getOauth2AutorizationResponse() {
+        return mOAuth2ParsedAuthorizationResponse;
+    }
+
+    public Map<String, String> getResultTokenMap() {
+        return mResultTokenMap;
+    }
+    
+    @Override
+    protected RemoteOperationResult run(WebdavClient client) {
+        RemoteOperationResult result = null;
+        PostMethod postMethod = null;
+        
+        try {
+            parseAuthorizationResponse();
+            if (mOAuth2ParsedAuthorizationResponse.keySet().contains(OAuth2Constants.KEY_ERROR)) {
+                if (OAuth2Constants.VALUE_ERROR_ACCESS_DENIED.equals(mOAuth2ParsedAuthorizationResponse.get(OAuth2Constants.KEY_ERROR))) {
+                    result = new RemoteOperationResult(ResultCode.OAUTH2_ERROR_ACCESS_DENIED);
+                } else {
+                    result = new RemoteOperationResult(ResultCode.OAUTH2_ERROR);
+                }
+            }
+            
+            if (result == null) { 
+                NameValuePair[] nameValuePairs = new NameValuePair[4];
+                nameValuePairs[0] = new NameValuePair(OAuth2Constants.KEY_GRANT_TYPE, mGrantType);
+                nameValuePairs[1] = new NameValuePair(OAuth2Constants.KEY_CODE, mOAuth2ParsedAuthorizationResponse.get(OAuth2Constants.KEY_CODE));            
+                nameValuePairs[2] = new NameValuePair(OAuth2Constants.KEY_REDIRECT_URI, mRedirectUri);       
+                nameValuePairs[3] = new NameValuePair(OAuth2Constants.KEY_CLIENT_ID, mClientId);
+                //nameValuePairs[4] = new NameValuePair(OAuth2Constants.KEY_SCOPE, mOAuth2ParsedAuthorizationResponse.get(OAuth2Constants.KEY_SCOPE));         
+                
+                postMethod = new PostMethod(client.getBaseUri().toString());
+                postMethod.setRequestBody(nameValuePairs);
+                int status = client.executeMethod(postMethod);
+                
+                String response = postMethod.getResponseBodyAsString();
+                if (response != null && response.length() > 0) {
+                    JSONObject tokenJson = new JSONObject(response);
+                    parseAccessTokenResult(tokenJson);
+                    if (mResultTokenMap.get(OAuth2Constants.KEY_ERROR) != null || mResultTokenMap.get(OAuth2Constants.KEY_ACCESS_TOKEN) == null) {
+                        result = new RemoteOperationResult(ResultCode.OAUTH2_ERROR);
+                    
+                    } else {
+                        result = new RemoteOperationResult(true, status);
+                    }
+                    
+                } else {
+                    client.exhaustResponse(postMethod.getResponseBodyAsStream());
+                    result = new RemoteOperationResult(false, status);
+                }
+            }
+            
+        } catch (Exception e) {
+            result = new RemoteOperationResult(e);
+            
+        } finally {
+            if (postMethod != null)
+                postMethod.releaseConnection();    // let the connection available for other methods
+            
+            if (result.isSuccess()) {
+                Log_OC.i(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage());
+            
+            } else if (result.getException() != null) {
+                Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage(), result.getException());
+                
+            } else if (result.getCode() == ResultCode.OAUTH2_ERROR) {
+                Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + ((mResultTokenMap != null) ? mResultTokenMap.get(OAuth2Constants.KEY_ERROR) : "NULL"));
+                    
+            } else {
+                Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage());
+            }
+        }
+        
+        return result;
+    }
+    
+    
+    private void parseAuthorizationResponse() {
+        String[] pairs = mOAuth2AuthorizationResponse.split("&");
+        int i = 0;
+        String key = "";
+        String value = "";
+        StringBuilder sb = new StringBuilder();
+        while (pairs.length > i) {
+            int j = 0;
+            String[] part = pairs[i].split("=");
+            while (part.length > j) {
+                String p = part[j];
+                if (j == 0) {
+                    key = p;
+                    sb.append(key + " = ");
+                } else if (j == 1) {
+                    value = p;
+                    mOAuth2ParsedAuthorizationResponse.put(key, value);
+                    sb.append(value + "\n");
+                }
+
+                Log_OC.v(TAG, "[" + i + "," + j + "] = " + p);
+                j++;
+            }
+            i++;
+        }
+    }
+
+
+    private void parseAccessTokenResult (JSONObject tokenJson) throws JSONException {
+        mResultTokenMap = new HashMap<String, String>();
+        
+        if (tokenJson.has(OAuth2Constants.KEY_ACCESS_TOKEN)) {
+            mResultTokenMap.put(OAuth2Constants.KEY_ACCESS_TOKEN, tokenJson.getString(OAuth2Constants.KEY_ACCESS_TOKEN));
+        }
+        if (tokenJson.has(OAuth2Constants.KEY_TOKEN_TYPE)) {
+            mResultTokenMap.put(OAuth2Constants.KEY_TOKEN_TYPE, tokenJson.getString(OAuth2Constants.KEY_TOKEN_TYPE));
+        }
+        if (tokenJson.has(OAuth2Constants.KEY_EXPIRES_IN)) {
+            mResultTokenMap.put(OAuth2Constants.KEY_EXPIRES_IN, tokenJson.getString(OAuth2Constants.KEY_EXPIRES_IN));
+        }
+        if (tokenJson.has(OAuth2Constants.KEY_REFRESH_TOKEN)) {
+            mResultTokenMap.put(OAuth2Constants.KEY_REFRESH_TOKEN, tokenJson.getString(OAuth2Constants.KEY_REFRESH_TOKEN));
+        }
+        if (tokenJson.has(OAuth2Constants.KEY_SCOPE)) {
+            mResultTokenMap.put(OAuth2Constants.KEY_SCOPE, tokenJson.getString(OAuth2Constants.KEY_SCOPE));
+        }
+        if (tokenJson.has(OAuth2Constants.KEY_ERROR)) {
+            mResultTokenMap.put(OAuth2Constants.KEY_ERROR, tokenJson.getString(OAuth2Constants.KEY_ERROR));
+        }
+        if (tokenJson.has(OAuth2Constants.KEY_ERROR_DESCRIPTION)) {
+            mResultTokenMap.put(OAuth2Constants.KEY_ERROR_DESCRIPTION, tokenJson.getString(OAuth2Constants.KEY_ERROR_DESCRIPTION));
+        }
+        if (tokenJson.has(OAuth2Constants.KEY_ERROR_URI)) {
+            mResultTokenMap.put(OAuth2Constants.KEY_ERROR_URI, tokenJson.getString(OAuth2Constants.KEY_ERROR_URI));
+        }
+    }
+
+}

+ 3 - 4
src/com/owncloud/android/operations/ConnectionCheckOperation.java → src/com/owncloud/android/operations/OwnCloudServerCheckOperation.java

@@ -30,21 +30,20 @@ import eu.alefzero.webdav.WebdavClient;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.Uri;
-import android.util.Log;
 
-public class ConnectionCheckOperation extends RemoteOperation {
+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 = ConnectionCheckOperation.class.getSimpleName();
+    private static final String TAG = OwnCloudServerCheckOperation.class.getSimpleName();
     
     private String mUrl;
     private RemoteOperationResult mLatestResult;
     private Context mContext;
     private OwnCloudVersion mOCVersion;
 
-    public ConnectionCheckOperation(String url, Context context) {
+    public OwnCloudServerCheckOperation(String url, Context context) {
         mUrl = url;
         mContext = context;
         mOCVersion = null;

+ 152 - 5
src/com/owncloud/android/operations/RemoteOperation.java

@@ -16,6 +16,21 @@
  */
 package com.owncloud.android.operations;
 
+import java.io.IOException;
+
+import org.apache.commons.httpclient.Credentials;
+
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.authentication.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 eu.alefzero.webdav.WebdavClient;
@@ -29,7 +44,15 @@ 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 */
@@ -38,16 +61,49 @@ public abstract class RemoteOperation implements Runnable {
 	/** 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_OC.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.
 	 */
@@ -59,6 +115,43 @@ public abstract class RemoteOperation implements Runnable {
 	}
 
 	
+    /**
+     * 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
 	 * 
@@ -115,20 +208,74 @@ public abstract class RemoteOperation implements Runnable {
 	 * 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_OC.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_OC.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;
+    }
+
 }

+ 30 - 5
src/com/owncloud/android/operations/RemoteOperationResult.java

@@ -32,8 +32,6 @@ import org.apache.commons.httpclient.HttpException;
 import org.apache.commons.httpclient.HttpStatus;
 import org.apache.jackrabbit.webdav.DavException;
 
-import android.util.Log;
-
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.network.CertificateCombinedException;
 
@@ -49,10 +47,37 @@ public class RemoteOperationResult implements Serializable {
 
     /** Generated - should be refreshed every time the class changes!! */
     private static final long serialVersionUID = -7805531062432602444L;
+    
     private static final String TAG = "RemoteOperationResult";
-
-    public enum ResultCode {
-        OK, OK_SSL, OK_NO_SSL, UNHANDLED_HTTP_CODE, UNAUTHORIZED, FILE_NOT_FOUND, INSTANCE_NOT_CONFIGURED, UNKNOWN_ERROR, WRONG_CONNECTION, TIMEOUT, INCORRECT_ADDRESS, HOST_NOT_AVAILABLE, NO_NETWORK_CONNECTION, SSL_ERROR, SSL_RECOVERABLE_PEER_UNVERIFIED, BAD_OC_VERSION, CANCELLED, INVALID_LOCAL_FILE_NAME, INVALID_OVERWRITE, CONFLICT, SYNC_CONFLICT, LOCAL_STORAGE_FULL, LOCAL_STORAGE_NOT_MOVED, LOCAL_STORAGE_NOT_COPIED, QUOTA_EXCEEDED
+    
+    public enum ResultCode { 
+        OK,
+        OK_SSL,
+        OK_NO_SSL,
+        UNHANDLED_HTTP_CODE,
+        UNAUTHORIZED,        
+        FILE_NOT_FOUND, 
+        INSTANCE_NOT_CONFIGURED, 
+        UNKNOWN_ERROR, 
+        WRONG_CONNECTION,  
+        TIMEOUT, 
+        INCORRECT_ADDRESS, 
+        HOST_NOT_AVAILABLE, 
+        NO_NETWORK_CONNECTION, 
+        SSL_ERROR,
+        SSL_RECOVERABLE_PEER_UNVERIFIED,
+        BAD_OC_VERSION,
+        CANCELLED, 
+        INVALID_LOCAL_FILE_NAME, 
+        INVALID_OVERWRITE,
+        CONFLICT, 
+        OAUTH2_ERROR,
+        SYNC_CONFLICT,
+        LOCAL_STORAGE_FULL, 
+        LOCAL_STORAGE_NOT_MOVED, 
+        LOCAL_STORAGE_NOT_COPIED, 
+        OAUTH2_ERROR_ACCESS_DENIED,
+        QUOTA_EXCEEDED
     }
 
     private boolean mSuccess = false;

+ 0 - 2
src/com/owncloud/android/operations/RemoveFileOperation.java

@@ -20,8 +20,6 @@ package com.owncloud.android.operations;
 import org.apache.commons.httpclient.HttpStatus;
 import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
 
-import android.util.Log;
-
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.OCFile;

+ 1 - 2
src/com/owncloud/android/operations/RenameFileOperation.java

@@ -24,7 +24,6 @@ import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
 //import org.apache.jackrabbit.webdav.client.methods.MoveMethod;
 
 import android.accounts.Account;
-import android.util.Log;
 
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.DataStorageManager;
@@ -42,7 +41,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;

+ 0 - 1
src/com/owncloud/android/operations/SynchronizeFileOperation.java

@@ -25,7 +25,6 @@ import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
 import android.accounts.Account;
 import android.content.Context;
 import android.content.Intent;
-import android.util.Log;
 
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.DataStorageManager;

+ 0 - 1
src/com/owncloud/android/operations/SynchronizeFolderOperation.java

@@ -34,7 +34,6 @@ import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
 
 import android.accounts.Account;
 import android.content.Context;
-import android.util.Log;
 
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.DataStorageManager;

+ 1 - 2
src/com/owncloud/android/operations/UpdateOCVersionOperation.java

@@ -25,11 +25,10 @@ import org.json.JSONObject;
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.content.Context;
-import android.util.Log;
 
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.authentication.AccountAuthenticator;
 import com.owncloud.android.Log_OC;
-import com.owncloud.android.authenticator.AccountAuthenticator;
 import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.utils.OwnCloudVersion;
 

+ 0 - 1
src/com/owncloud/android/providers/FileContentProvider.java

@@ -37,7 +37,6 @@ import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.net.Uri;
 import android.text.TextUtils;
-import android.util.Log;
 
 /**
  * The ContentProvider for the ownCloud App.

+ 1 - 1
src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java

@@ -142,7 +142,7 @@ public abstract class AbstractOwnCloudSyncAdapter extends
         return null;
     }
 
-    protected void initClientForCurrentAccount() throws UnknownHostException {
+    protected void initClientForCurrentAccount() throws OperationCanceledException, AuthenticatorException, IOException {
         if (AccountUtils.constructFullURLForAccount(getContext(), account) == null) {
             throw new UnknownHostException();
         }

+ 1 - 1
src/com/owncloud/android/syncadapter/ContactSyncAdapter.java

@@ -25,7 +25,7 @@ import org.apache.http.client.methods.HttpPut;
 import org.apache.http.entity.ByteArrayEntity;
 
 import com.owncloud.android.AccountUtils;
-import com.owncloud.android.authenticator.AccountAuthenticator;
+import com.owncloud.android.authentication.AccountAuthenticator;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;

+ 31 - 12
src/com/owncloud/android/syncadapter/FileSyncAdapter.java

@@ -19,7 +19,6 @@
 package com.owncloud.android.syncadapter;
 
 import java.io.IOException;
-import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -29,6 +28,7 @@ import org.apache.jackrabbit.webdav.DavException;
 
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
+import com.owncloud.android.authentication.AuthenticatorActivity;
 import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
@@ -38,6 +38,7 @@ import com.owncloud.android.operations.UpdateOCVersionOperation;
 import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.ui.activity.ErrorsWhileCopyingHandlerActivity;
 import android.accounts.Account;
+import android.accounts.AccountsException;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -47,13 +48,13 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.SyncResult;
 import android.os.Bundle;
-import android.util.Log;
 
 /**
  * SyncAdapter implementation for syncing sample SyncAdapter contacts to the
  * platform ContactOperations provider.
  * 
  * @author Bartek Przybylski
+ * @author David A. Velasco
  */
 public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
 
@@ -103,8 +104,13 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
         this.setStorageManager(new FileDataStorageManager(account, getContentProvider()));
         try {
             this.initClientForCurrentAccount();
-        } catch (UnknownHostException e) {
-            /// the account is unknown for the Synchronization Manager. unreachable for this context; don't try this again
+        } catch (IOException e) {
+            /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again
+            mSyncResult.tooManyRetries = true;
+            notifyFailedSynchronization();
+            return;
+        } catch (AccountsException e) {
+            /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again
             mSyncResult.tooManyRetries = true;
             notifyFailedSynchronization();
             return;
@@ -147,7 +153,6 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
         }
         
     }
-
     
     /**
      * Called by system SyncManager when a synchronization is required to be cancelled.
@@ -173,7 +178,6 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
             mLastFailedResult = result; 
         }
     }
-
     
     
     /**
@@ -292,12 +296,28 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
     private void notifyFailedSynchronization() {
         Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_ticker), System.currentTimeMillis());
         notification.flags |= Notification.FLAG_AUTO_CANCEL;
-        // TODO put something smart in the contentIntent below
+        boolean needsToUpdateCredentials = (mLastFailedResult != null && mLastFailedResult.getCode() == ResultCode.UNAUTHORIZED);
+        // TODO put something smart in the contentIntent below for all the possible errors
         notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);
-        notification.setLatestEventInfo(getContext().getApplicationContext(), 
-                                        getContext().getString(R.string.sync_fail_ticker), 
-                                        String.format(getContext().getString(R.string.sync_fail_content), getAccount().name), 
-                                        notification.contentIntent);
+        if (needsToUpdateCredentials) {
+            // let the user update credentials with one click
+            Intent updateAccountCredentials = new Intent(getContext(), AuthenticatorActivity.class);
+            updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, getAccount());
+            updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);
+            updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+            updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);
+            notification.contentIntent = PendingIntent.getActivity(getContext(), (int)System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT);
+            notification.setLatestEventInfo(getContext().getApplicationContext(), 
+                    getContext().getString(R.string.sync_fail_ticker), 
+                    String.format(getContext().getString(R.string.sync_fail_content_unauthorized), getAccount().name), 
+                    notification.contentIntent);
+        } else {
+            notification.setLatestEventInfo(getContext().getApplicationContext(), 
+                                            getContext().getString(R.string.sync_fail_ticker), 
+                                            String.format(getContext().getString(R.string.sync_fail_content), getAccount().name), 
+                                            notification.contentIntent);
+        }
         ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_ticker, notification);
     }
 
@@ -331,7 +351,6 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
             ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_conflicts_in_favourites_ticker, notification);
         } 
     }
-
     
     /**
      * Notifies the user about local copies of files out of the ownCloud local directory that were 'forgotten' because 

+ 4 - 5
src/com/owncloud/android/ui/activity/AccountSelectActivity.java

@@ -32,7 +32,6 @@ import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
-import android.util.Log;
 import android.view.ContextMenu;
 import android.view.View;
 import android.view.ViewGroup;
@@ -49,8 +48,8 @@ import com.actionbarsherlock.view.Menu;
 import com.actionbarsherlock.view.MenuInflater;
 import com.actionbarsherlock.view.MenuItem;
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.authentication.AccountAuthenticator;
 import com.owncloud.android.Log_OC;
-import com.owncloud.android.authenticator.AccountAuthenticator;
 
 import com.owncloud.android.R;
 
@@ -95,10 +94,10 @@ public class AccountSelectActivity extends SherlockListActivity implements
                 /// 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);
@@ -136,7 +135,7 @@ public class AccountSelectActivity extends SherlockListActivity implements
             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;
         }

+ 0 - 609
src/com/owncloud/android/ui/activity/AuthenticatorActivity.java

@@ -1,609 +0,0 @@
-/* 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 version 2,
- *   as published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.ui.activity;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import com.owncloud.android.AccountUtils;
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.authenticator.AccountAuthenticator;
-import com.owncloud.android.authenticator.AuthenticationRunnable;
-import com.owncloud.android.authenticator.OnAuthenticationResultListener;
-import com.owncloud.android.authenticator.OnConnectCheckListener;
-import com.owncloud.android.ui.dialog.SslValidatorDialog;
-import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;
-import com.owncloud.android.network.OwnCloudClientUtils;
-import com.owncloud.android.operations.ConnectionCheckOperation;
-import com.owncloud.android.operations.OnRemoteOperationListener;
-import com.owncloud.android.operations.RemoteOperation;
-import com.owncloud.android.operations.RemoteOperationResult;
-
-import android.accounts.Account;
-import android.accounts.AccountAuthenticatorActivity;
-import android.accounts.AccountManager;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.ProgressDialog;
-import android.content.ContentResolver;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.preference.PreferenceManager;
-import android.text.InputType;
-import android.util.Log;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnFocusChangeListener;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.TextView;
-import com.owncloud.android.R;
-
-import eu.alefzero.webdav.WebdavClient;
-
-/**
- * This Activity is used to add an ownCloud account to the App
- * 
- * @author Bartek Przybylski
- * 
- */
-public class AuthenticatorActivity extends AccountAuthenticatorActivity
-        implements OnAuthenticationResultListener, OnConnectCheckListener, OnRemoteOperationListener, OnSslValidatorListener, 
-        OnFocusChangeListener, OnClickListener {
-
-    private static final int DIALOG_LOGIN_PROGRESS = 0;
-    private static final int DIALOG_SSL_VALIDATOR = 1;
-    private static final int DIALOG_CERT_NOT_SAVED = 2;
-
-    private static final String TAG = "AuthActivity";
-
-    private Thread mAuthThread;
-    private AuthenticationRunnable mAuthRunnable;
-    //private ConnectionCheckerRunnable mConnChkRunnable = null;
-    private ConnectionCheckOperation mConnChkRunnable;
-    private final Handler mHandler = new Handler();
-    private String mBaseUrl;
-    
-    private static final String STATUS_TEXT = "STATUS_TEXT";
-    private static final String STATUS_ICON = "STATUS_ICON";
-    private static final String STATUS_CORRECT = "STATUS_CORRECT";
-    private static final String IS_SSL_CONN = "IS_SSL_CONN";
-    private int mStatusText, mStatusIcon;
-    private boolean mStatusCorrect, mIsSslConn;
-    private RemoteOperationResult mLastSslUntrustedServerResult;
-
-    public static final String PARAM_USERNAME = "param_Username";
-    public static final String PARAM_HOSTNAME = "param_Hostname";
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
-        setContentView(R.layout.account_setup);
-        ImageView iv = (ImageView) findViewById(R.id.refreshButton);
-        ImageView iv2 = (ImageView) findViewById(R.id.viewPassword);
-        TextView tv = (TextView) findViewById(R.id.host_URL);
-        TextView tv2 = (TextView) findViewById(R.id.account_password);
-
-        if (savedInstanceState != null) {
-            mStatusIcon = savedInstanceState.getInt(STATUS_ICON);
-            mStatusText = savedInstanceState.getInt(STATUS_TEXT);
-            mStatusCorrect = savedInstanceState.getBoolean(STATUS_CORRECT);
-            mIsSslConn = savedInstanceState.getBoolean(IS_SSL_CONN);
-            setResultIconAndText(mStatusIcon, mStatusText);
-            findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);
-            if (!mStatusCorrect)
-                iv.setVisibility(View.VISIBLE);
-            else
-                iv.setVisibility(View.INVISIBLE);
-
-        } else {
-            mStatusText = mStatusIcon = 0;
-            mStatusCorrect = false;
-            mIsSslConn = false;
-        }
-        iv.setOnClickListener(this);
-        iv2.setOnClickListener(this);
-        tv.setOnFocusChangeListener(this);
-        tv2.setOnFocusChangeListener(this);
-
-        Button b = (Button) findViewById(R.id.account_register);
-        if (b != null) {
-            b.setText(String.format(getString(R.string.auth_register), getString(R.string.app_name)));
-        }
-    }
-
-    @Override
-    protected void onSaveInstanceState(Bundle outState) {
-        outState.putInt(STATUS_ICON, mStatusIcon);
-        outState.putInt(STATUS_TEXT, mStatusText);
-        outState.putBoolean(STATUS_CORRECT, mStatusCorrect);
-        super.onSaveInstanceState(outState);
-    }
-
-    @Override
-    protected Dialog onCreateDialog(int id) {
-        Dialog dialog = null;
-        switch (id) {
-        case DIALOG_LOGIN_PROGRESS: {
-            ProgressDialog working_dialog = new ProgressDialog(this);
-            working_dialog.setMessage(getResources().getString(
-                    R.string.auth_trying_to_login));
-            working_dialog.setIndeterminate(true);
-            working_dialog.setCancelable(true);
-            working_dialog
-                    .setOnCancelListener(new DialogInterface.OnCancelListener() {
-                        @Override
-                        public void onCancel(DialogInterface dialog) {
-                            Log_OC.i(TAG, "Login canceled");
-                            if (mAuthThread != null) {
-                                mAuthThread.interrupt();
-                                finish();
-                            }
-                        }
-                    });
-            dialog = working_dialog;
-            break;
-        }
-        case DIALOG_SSL_VALIDATOR: {
-            dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);
-            break;
-        }
-        case DIALOG_CERT_NOT_SAVED: {
-            AlertDialog.Builder builder = new AlertDialog.Builder(this);
-            builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));
-            builder.setCancelable(false);
-            builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        dialog.dismiss();
-                    };
-                });
-            dialog = builder.create();
-            break;
-        }
-        default:
-            Log_OC.e(TAG, "Incorrect dialog called with id = " + id);
-        }
-        return dialog;
-    }
-
-    @Override
-    protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
-        switch (id) {
-        case DIALOG_LOGIN_PROGRESS:
-        case DIALOG_CERT_NOT_SAVED:
-            break;
-        case DIALOG_SSL_VALIDATOR: {
-            ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);
-            break;
-        }
-        default:
-            Log_OC.e(TAG, "Incorrect dialog called with id = " + id);
-        }
-    }
-
-    public void onAuthenticationResult(boolean success, String message) {
-        if (success) {
-            TextView username_text = (TextView) findViewById(R.id.account_username), password_text = (TextView) findViewById(R.id.account_password);
-
-            URL url;
-            try {
-                url = new URL(message);
-            } catch (MalformedURLException e) {
-                // should never happen
-                Log_OC.e(getClass().getName(), "Malformed URL: " + message);
-                return;
-            }
-
-            String username = username_text.getText().toString().trim();
-            String accountName = username + "@" + url.getHost();
-            if (url.getPort() >= 0) {
-                accountName += ":" + url.getPort();
-            }
-            Account account = new Account(accountName,
-                    AccountAuthenticator.ACCOUNT_TYPE);
-            AccountManager accManager = AccountManager.get(this);
-            accManager.addAccountExplicitly(account, password_text.getText()
-                    .toString(), null);
-
-            // Add this account as default in the preferences, if there is none
-            // already
-            Account defaultAccount = AccountUtils
-                    .getCurrentOwnCloudAccount(this);
-            if (defaultAccount == null) {
-                SharedPreferences.Editor editor = PreferenceManager
-                        .getDefaultSharedPreferences(this).edit();
-                editor.putString("select_oc_account", accountName);
-                editor.commit();
-            }
-
-            final Intent intent = new Intent();
-            intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE,
-                    AccountAuthenticator.ACCOUNT_TYPE);
-            intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
-            intent.putExtra(AccountManager.KEY_AUTHTOKEN,
-                    AccountAuthenticator.ACCOUNT_TYPE);
-            intent.putExtra(AccountManager.KEY_USERDATA, username);
-
-            accManager.setUserData(account,
-                    AccountAuthenticator.KEY_OC_VERSION, mConnChkRunnable
-                            .getDiscoveredVersion().toString());
-            
-            accManager.setUserData(account,
-                    AccountAuthenticator.KEY_OC_BASE_URL, mBaseUrl);
-
-            setAccountAuthenticatorResult(intent.getExtras());
-            setResult(RESULT_OK, intent);
-            Bundle bundle = new Bundle();
-            bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
-            //getContentResolver().startSync(ProviderTableMeta.CONTENT_URI,
-            //        bundle);
-            ContentResolver.requestSync(account, "org.owncloud", bundle);
-
-            /*
-             * if
-             * (mConnChkRunnable.getDiscoveredVersion().compareTo(OwnCloudVersion
-             * .owncloud_v2) >= 0) { Intent i = new Intent(this,
-             * ExtensionsAvailableActivity.class); startActivity(i); }
-             */
-
-            finish();
-        } else {
-            try {
-                dismissDialog(DIALOG_LOGIN_PROGRESS);
-            } catch (IllegalArgumentException e) {
-                // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens
-            }
-            TextView tv = (TextView) findViewById(R.id.account_username);
-            tv.setError(message + "        ");  // the extra spaces are a workaround for an ugly bug: 
-                                                // 1. insert wrong credentials and connect
-                                                // 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
-                                                // 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
-                                                // Seen, at least, in Android 2.x devices
-        }
-    }
-    public void onCancelClick(View view) {
-        setResult(RESULT_CANCELED);
-        finish();
-    }
-    
-    public void onOkClick(View view) {
-        String prefix = "";
-        String url = ((TextView) findViewById(R.id.host_URL)).getText()
-                .toString().trim();
-        if (mIsSslConn) {
-            prefix = "https://";
-        } else {
-            prefix = "http://";
-        }
-        if (url.toLowerCase().startsWith("http://")
-                || url.toLowerCase().startsWith("https://")) {
-            prefix = "";
-        }
-        continueConnection(prefix);
-    }
-    
-    public void onRegisterClick(View view) {
-        Intent register = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_account_register)));
-        setResult(RESULT_CANCELED);
-        startActivity(register);
-    }
-
-    private void continueConnection(String prefix) {
-        String url = ((TextView) findViewById(R.id.host_URL)).getText()
-                .toString().trim();
-        String username = ((TextView) findViewById(R.id.account_username))
-                .getText().toString();
-        String password = ((TextView) findViewById(R.id.account_password))
-                .getText().toString();
-        if (url.endsWith("/"))
-            url = url.substring(0, url.length() - 1);
-
-        URL uri = null;
-        String webdav_path = AccountUtils.getWebdavPath(mConnChkRunnable
-                .getDiscoveredVersion());
-        
-        if (webdav_path == null) {
-            onAuthenticationResult(false, getString(R.string.auth_bad_oc_version_title));
-            return;
-        }
-        
-        try {
-            mBaseUrl = prefix + url;
-            String url_str = prefix + url + webdav_path;
-            uri = new URL(url_str);
-        } catch (MalformedURLException e) {
-            // should never happen
-            onAuthenticationResult(false, getString(R.string.auth_incorrect_address_title));
-            return;
-        }
-
-        showDialog(DIALOG_LOGIN_PROGRESS);
-        mAuthRunnable = new AuthenticationRunnable(uri, username, password, this);
-        mAuthRunnable.setOnAuthenticationResultListener(this, mHandler);
-        mAuthThread = new Thread(mAuthRunnable);
-        mAuthThread.start();
-    }
-
-    @Override
-    public void onConnectionCheckResult(ResultType type) {
-        mStatusText = mStatusIcon = 0;
-        mStatusCorrect = false;
-        String t_url = ((TextView) findViewById(R.id.host_URL)).getText()
-                .toString().trim().toLowerCase();
-
-        switch (type) {
-        case OK_SSL:
-            mIsSslConn = true;
-            mStatusIcon = android.R.drawable.ic_secure;
-            mStatusText = R.string.auth_secure_connection;
-            mStatusCorrect = true;
-            break;
-        case OK_NO_SSL:
-            mIsSslConn = false;
-            mStatusCorrect = true;
-            if (t_url.startsWith("http://") ) {
-                mStatusText = R.string.auth_connection_established;
-                mStatusIcon = R.drawable.ic_ok;
-            } else {
-                mStatusText = R.string.auth_nossl_plain_ok_title;
-                mStatusIcon = android.R.drawable.ic_partial_secure;
-            }
-            break;
-        case BAD_OC_VERSION:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_bad_oc_version_title;
-            break;
-        case WRONG_CONNECTION:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_wrong_connection_title;
-            break;
-        case TIMEOUT:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_timeout_title;
-            break;
-        case INCORRECT_ADDRESS:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_incorrect_address_title;
-            break;
-        case SSL_UNVERIFIED_SERVER:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_ssl_unverified_server_title;
-            break;
-        case SSL_INIT_ERROR:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_ssl_general_error_title;
-            break;
-        case HOST_NOT_AVAILABLE:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_unknown_host_title;
-            break;
-        case NO_NETWORK_CONNECTION:
-            mStatusIcon = R.drawable.no_network;
-            mStatusText = R.string.auth_no_net_conn_title;
-            break;
-        case INSTANCE_NOT_CONFIGURED:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_not_configured_title;
-            break;
-        case UNKNOWN_ERROR:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_unknown_error_title;
-            break;
-        case FILE_NOT_FOUND:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_incorrect_path_title;
-            break;
-        default:
-            Log_OC.e(TAG, "Incorrect connection checker result type: " + type);
-        }
-        setResultIconAndText(mStatusIcon, mStatusText);
-        if (!mStatusCorrect)
-            findViewById(R.id.refreshButton).setVisibility(View.VISIBLE);
-        else
-            findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE);
-        findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);
-    }
-
-    @Override
-    public void onFocusChange(View view, boolean hasFocus) {
-        if (view.getId() == R.id.host_URL) {
-            if (!hasFocus) {
-                TextView tv = ((TextView) findViewById(R.id.host_URL));
-                String uri = tv.getText().toString().trim();
-                if (uri.length() != 0) {
-                    setResultIconAndText(R.drawable.progress_small,
-                            R.string.auth_testing_connection);
-                    //mConnChkRunnable = new ConnectionCheckerRunnable(uri, this);
-                    mConnChkRunnable = new ConnectionCheckOperation(uri, this);
-                    //mConnChkRunnable.setListener(this, mHandler);
-                    //mAuthThread = new Thread(mConnChkRunnable);
-                    //mAuthThread.start();
-            		WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this);
-                    mAuthThread = mConnChkRunnable.execute(client, this, mHandler);
-                } else {
-                    findViewById(R.id.refreshButton).setVisibility(
-                            View.INVISIBLE);
-                    setResultIconAndText(0, 0);
-                }
-            } else {
-                // avoids that the 'connect' button can be clicked if the test was previously passed
-                findViewById(R.id.buttonOK).setEnabled(false); 
-            }
-        } else if (view.getId() == R.id.account_password) {
-            ImageView iv = (ImageView) findViewById(R.id.viewPassword);
-            if (hasFocus) {
-                iv.setVisibility(View.VISIBLE);
-            } else {
-                TextView v = (TextView) findViewById(R.id.account_password);
-                int input_type = InputType.TYPE_CLASS_TEXT
-                        | InputType.TYPE_TEXT_VARIATION_PASSWORD;
-                v.setInputType(input_type);
-                iv.setVisibility(View.INVISIBLE);
-            }
-        }
-    }
-
-    private void setResultIconAndText(int drawable_id, int text_id) {
-        ImageView iv = (ImageView) findViewById(R.id.action_indicator);
-        TextView tv = (TextView) findViewById(R.id.status_text);
-
-        if (drawable_id == 0 && text_id == 0) {
-            iv.setVisibility(View.INVISIBLE);
-            tv.setVisibility(View.INVISIBLE);
-        } else {
-            iv.setImageResource(drawable_id);
-            tv.setText(text_id);
-            iv.setVisibility(View.VISIBLE);
-            tv.setVisibility(View.VISIBLE);
-        }
-    }
-
-    @Override
-    public void onClick(View v) {
-        if (v.getId() == R.id.refreshButton) {
-            onFocusChange(findViewById(R.id.host_URL), false);
-        } else if (v.getId() == R.id.viewPassword) {
-            EditText view = (EditText) findViewById(R.id.account_password);
-            int selectionStart = view.getSelectionStart();
-            int selectionEnd = view.getSelectionEnd();
-            int input_type = view.getInputType();
-            if ((input_type & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
-                input_type = InputType.TYPE_CLASS_TEXT
-                        | InputType.TYPE_TEXT_VARIATION_PASSWORD;
-            } else {
-                input_type = InputType.TYPE_CLASS_TEXT
-                        | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
-            }
-            view.setInputType(input_type);
-            view.setSelection(selectionStart, selectionEnd);
-        }
-    }
-
-	@Override
-	public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
-		if (operation.equals(mConnChkRunnable)) {
-		    
-	        mStatusText = mStatusIcon = 0;
-	        mStatusCorrect = false;
-	        String t_url = ((TextView) findViewById(R.id.host_URL)).getText()
-	                .toString().trim().toLowerCase();
-	        
-	        switch (result.getCode()) {
-	        case OK_SSL:
-	            mIsSslConn = true;
-	            mStatusIcon = android.R.drawable.ic_secure;
-	            mStatusText = R.string.auth_secure_connection;
-	            mStatusCorrect = true;
-	            break;
-	            
-	        case OK_NO_SSL:
-	        case OK:
-	            mIsSslConn = false;
-	            mStatusCorrect = true;
-	            if (t_url.startsWith("http://") ) {
-	                mStatusText = R.string.auth_connection_established;
-	                mStatusIcon = R.drawable.ic_ok;
-	            } else {
-	                mStatusText = R.string.auth_nossl_plain_ok_title;
-	                mStatusIcon = android.R.drawable.ic_partial_secure;
-	            }
-	            break;
-	        
-	            
-	        case BAD_OC_VERSION:
-	            mStatusIcon = R.drawable.common_error;
-	            mStatusText = R.string.auth_bad_oc_version_title;
-	            break;
-	        case WRONG_CONNECTION:
-	            mStatusIcon = R.drawable.common_error;
-	            mStatusText = R.string.auth_wrong_connection_title;
-	            break;
-	        case TIMEOUT:
-	            mStatusIcon = R.drawable.common_error;
-	            mStatusText = R.string.auth_timeout_title;
-	            break;
-	        case INCORRECT_ADDRESS:
-	            mStatusIcon = R.drawable.common_error;
-	            mStatusText = R.string.auth_incorrect_address_title;
-	            break;
-	            
-            case SSL_RECOVERABLE_PEER_UNVERIFIED:
-                mStatusIcon = R.drawable.common_error;
-                mStatusText = R.string.auth_ssl_unverified_server_title;
-                mLastSslUntrustedServerResult = result;
-                showDialog(DIALOG_SSL_VALIDATOR); 
-                break;
-	            
-            case SSL_ERROR:
-                mStatusIcon = R.drawable.common_error;
-                mStatusText = R.string.auth_ssl_general_error_title;
-                break;
-                
-	        case HOST_NOT_AVAILABLE:
-	            mStatusIcon = R.drawable.common_error;
-	            mStatusText = R.string.auth_unknown_host_title;
-	            break;
-	        case NO_NETWORK_CONNECTION:
-	            mStatusIcon = R.drawable.no_network;
-	            mStatusText = R.string.auth_no_net_conn_title;
-	            break;
-	        case INSTANCE_NOT_CONFIGURED:
-	            mStatusIcon = R.drawable.common_error;
-	            mStatusText = R.string.auth_not_configured_title;
-	            break;
-	        case FILE_NOT_FOUND:
-	            mStatusIcon = R.drawable.common_error;
-	            mStatusText = R.string.auth_incorrect_path_title;
-	            break;
-            case UNHANDLED_HTTP_CODE:
-            case UNKNOWN_ERROR:
-                mStatusIcon = R.drawable.common_error;
-                mStatusText = R.string.auth_unknown_error_title;
-                break;
-	        default:
-	            Log_OC.e(TAG, "Incorrect connection checker result type: " + result.getHttpCode());
-	        }
-	        setResultIconAndText(mStatusIcon, mStatusText);
-	        if (!mStatusCorrect)
-	            findViewById(R.id.refreshButton).setVisibility(View.VISIBLE);
-	        else
-	            findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE);
-	        findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);
-		}
-	}
-
-	
-    public void onSavedCertificate() {
-        mAuthThread = mConnChkRunnable.retry(this, mHandler);                
-    }
-
-    @Override
-    public void onFailedSavingCertificate() {
-        showDialog(DIALOG_CERT_NOT_SAVED);
-    }
-    
-}

+ 0 - 1
src/com/owncloud/android/ui/activity/ErrorsWhileCopyingHandlerActivity.java

@@ -28,7 +28,6 @@ import android.os.Bundle;
 import android.os.Handler;
 import android.support.v4.app.DialogFragment;
 import android.text.method.ScrollingMovementMethod;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;

+ 17 - 11
src/com/owncloud/android/ui/activity/FailedUploadActivity.java

@@ -1,3 +1,20 @@
+/* ownCloud Android client application
+ *   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 version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
 package com.owncloud.android.ui.activity;
 
 import android.app.Activity;
@@ -14,18 +31,7 @@ import com.owncloud.android.R;
  * 
  * The entry-point for this activity is the 'Failed upload Notification"
  * 
- * 
  * @author andomaex / Matthias Baumann
- * 
- *         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. (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 de/
  */
 public class FailedUploadActivity extends Activity {
 

+ 0 - 1
src/com/owncloud/android/ui/activity/FileDetailActivity.java

@@ -31,7 +31,6 @@ import android.os.Bundle;
 import android.os.IBinder;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
 
 import com.actionbarsherlock.app.ActionBar;
 import com.actionbarsherlock.app.SherlockFragmentActivity;

+ 47 - 151
src/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -23,7 +23,6 @@ import java.io.File;
 import android.accounts.Account;
 import android.app.AlertDialog;
 import android.app.ProgressDialog;
-import android.app.AlertDialog.Builder;
 import android.app.Dialog;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -35,8 +34,6 @@ import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-import android.content.pm.PackageInfo;
 import android.content.res.Resources.NotFoundException;
 import android.database.Cursor;
 import android.net.Uri;
@@ -47,11 +44,9 @@ import android.preference.PreferenceManager;
 import android.provider.MediaStore;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ArrayAdapter;
-import android.widget.EditText;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -65,7 +60,7 @@ import com.actionbarsherlock.view.Window;
 import com.owncloud.android.AccountUtils;
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
-import com.owncloud.android.authenticator.AccountAuthenticator;
+import com.owncloud.android.authentication.AccountAuthenticator;
 import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
@@ -74,7 +69,7 @@ import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileObserverService;
 import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
-import com.owncloud.android.network.OwnCloudClientUtils;
+import com.owncloud.android.operations.CreateFolderOperation;
 import com.owncloud.android.operations.OnRemoteOperationListener;
 import com.owncloud.android.operations.RemoteOperation;
 import com.owncloud.android.operations.RemoteOperationResult;
@@ -83,7 +78,6 @@ import com.owncloud.android.operations.RenameFileOperation;
 import com.owncloud.android.operations.SynchronizeFileOperation;
 import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.syncadapter.FileSyncService;
-import com.owncloud.android.ui.dialog.ChangelogDialog;
 import com.owncloud.android.ui.dialog.EditNameDialog;
 import com.owncloud.android.ui.dialog.SslValidatorDialog;
 import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
@@ -95,8 +89,6 @@ import com.owncloud.android.ui.preview.PreviewImageActivity;
 import com.owncloud.android.ui.preview.PreviewImageFragment;
 import com.owncloud.android.ui.preview.PreviewMediaFragment;
 
-import eu.alefzero.webdav.WebdavClient;
-
 /**
  * Displays, what files the user has available in his ownCloud.
  * 
@@ -126,13 +118,10 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
     private boolean mBackFromCreatingFirstAccount;
     
     private static final int DIALOG_SETUP_ACCOUNT = 0;
-    private static final int DIALOG_CREATE_DIR = 1;
-    public static final int DIALOG_SHORT_WAIT = 3;
-    private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 4;
-    private static final int DIALOG_SSL_VALIDATOR = 5;
-    private static final int DIALOG_CERT_NOT_SAVED = 6;
-    private static final String DIALOG_CHANGELOG_TAG = "DIALOG_CHANGELOG";
-
+    public static final int DIALOG_SHORT_WAIT = 1;
+    private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 2;
+    private static final int DIALOG_SSL_VALIDATOR = 3;
+    private static final int DIALOG_CERT_NOT_SAVED = 4;
     
     private static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;
     private static final int ACTION_SELECT_MULTIPLE_FILES = 2;
@@ -147,6 +136,8 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         Log_OC.d(getClass().toString(), "onCreate() start");
         super.onCreate(savedInstanceState);
 
+        mHandler = new Handler();
+
         /// Load of parameters from received intent
         Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);
         if (account != null && AccountUtils.setCurrentOwnCloudAccount(this, account.name)) {
@@ -233,46 +224,18 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         setSupportProgressBarIndeterminateVisibility(false);        // always AFTER setContentView(...) ; to workaround bug in its implementation
         
         
-        // show changelog, if needed
-        //showChangeLog();
         mBackFromCreatingFirstAccount = false;
         
         Log_OC.d(getClass().toString(), "onCreate() end");
     }
 
     
-    /**
-     * Shows a dialog with the change log of the current version after each app update
-     * 
-     *  TODO make it permanent; by now, only to advice the workaround app for 4.1.x
-     */
-    private void showChangeLog() {
-        if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.JELLY_BEAN) {
-            final String KEY_VERSION = "version";
-            SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
-            int currentVersionNumber = 0;
-            int savedVersionNumber = sharedPref.getInt(KEY_VERSION, 0);
-            try {
-                PackageInfo pi          = getPackageManager().getPackageInfo(getPackageName(), 0);
-                currentVersionNumber    = pi.versionCode;
-            } catch (Exception e) {}
-     
-            if (currentVersionNumber > savedVersionNumber) {
-                ChangelogDialog.newInstance(true).show(getSupportFragmentManager(), DIALOG_CHANGELOG_TAG);
-                Editor editor   = sharedPref.edit();
-                editor.putInt(KEY_VERSION, currentVersionNumber);
-                editor.commit();
-            }
-        }
-    }
-    
-
     /**
      * Launches the account creation activity. To use when no ownCloud account is available
      */
     private void createFirstAccount() {
         Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);
-        intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });
+        intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTHORITY });
         startActivity(intent);  // the new activity won't be created until this.onStart() and this.onResume() are finished;
     }
 
@@ -386,12 +349,12 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
     }
 
     private void startSynchronization() {
-        ContentResolver.cancelSync(null, AccountAuthenticator.AUTH_TOKEN_TYPE);   // cancel the current synchronizations of any ownCloud account
+        ContentResolver.cancelSync(null, AccountAuthenticator.AUTHORITY);   // cancel the current synchronizations of any ownCloud account
         Bundle bundle = new Bundle();
         bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
         ContentResolver.requestSync(
                 AccountUtils.getCurrentOwnCloudAccount(this),
-                AccountAuthenticator.AUTH_TOKEN_TYPE, bundle);
+                AccountAuthenticator.AUTHORITY, bundle);
     }
 
 
@@ -545,7 +508,6 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         outState.putParcelable(FileDetailActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
         Log_OC.d(getClass().toString(), "onSaveInstanceState() end");
     }
-
     
     @Override
     protected void onResume() {
@@ -651,53 +613,6 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
             dialog = builder.create();
             break;
         }
-        case DIALOG_CREATE_DIR: {
-            builder = new Builder(this);
-            final EditText dirNameInput = new EditText(getBaseContext());
-            builder.setView(dirNameInput);
-            builder.setTitle(R.string.uploader_info_dirname);
-            int typed_color = getResources().getColor(R.color.setup_text_typed);
-            dirNameInput.setTextColor(typed_color);
-            builder.setPositiveButton(android.R.string.ok,
-                    new OnClickListener() {
-                        public void onClick(DialogInterface dialog, int which) {
-                            String directoryName = dirNameInput.getText().toString();
-                            if (directoryName.trim().length() == 0) {
-                                dialog.cancel();
-                                return;
-                            }
-    
-                            // Figure out the path where the dir needs to be created
-                            String path;
-                            if (mCurrentDir == null) {
-                                // this is just a patch; we should ensure that mCurrentDir never is null
-                                if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) {
-                                    OCFile file = new OCFile(OCFile.PATH_SEPARATOR);
-                                    mStorageManager.saveFile(file);
-                                }
-                                mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);
-                            }
-                            path = FileDisplayActivity.this.mCurrentDir.getRemotePath();
-                            
-                            // Create directory
-                            path += directoryName + OCFile.PATH_SEPARATOR;
-                            Thread thread = new Thread(new DirectoryCreator(path,  AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), new Handler()));
-                            thread.start();
-                            
-                            dialog.dismiss();
-                            
-                            showDialog(DIALOG_SHORT_WAIT);
-                        }
-                    });
-            builder.setNegativeButton(R.string.common_cancel,
-                    new OnClickListener() {
-                        public void onClick(DialogInterface dialog, int which) {
-                            dialog.cancel();
-                        }
-                    });
-            dialog = builder.create();
-            break;
-        }
         case DIALOG_SHORT_WAIT: {
             ProgressDialog working_dialog = new ProgressDialog(this);
             working_dialog.setMessage(getResources().getString(
@@ -818,57 +733,6 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         return !mDirectories.isEmpty();
     }
 
-    private class DirectoryCreator implements Runnable {
-        private String mTargetPath;
-        private Account mAccount;
-        private Handler mHandler; 
-    
-        public DirectoryCreator(String targetPath, Account account, Handler handler) {
-            mTargetPath = targetPath;
-            mAccount = account;
-            mHandler = handler;
-        }
-    
-        @Override
-        public void run() {
-            WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext());
-            boolean created = wdc.createDirectory(mTargetPath);
-            if (created) {
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() { 
-                        dismissDialog(DIALOG_SHORT_WAIT);
-                        
-                        // Save new directory in local database
-                        OCFile newDir = new OCFile(mTargetPath);
-                        newDir.setMimetype("DIR");
-                        newDir.setParentId(mCurrentDir.getFileId());
-                        mStorageManager.saveFile(newDir);
-    
-                        // Display the new folder right away
-                        mFileList.listDirectory();
-                    }
-                });
-                
-            } else {
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        dismissDialog(DIALOG_SHORT_WAIT);
-                        try {
-                            Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); 
-                            msg.show();
-                        
-                        } catch (NotFoundException e) {
-                            Log_OC.e(TAG, "Error while trying to show fail message ", e);
-                        }
-                    }
-                });
-            }
-        }
-    
-    }
-
     // Custom array adapter to override text colors
     private class CustomArrayAdapter<T> extends ArrayAdapter<T> {
     
@@ -1283,6 +1147,9 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
             
         } else if (operation instanceof SynchronizeFileOperation) {
             onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);
+
+        } else if (operation instanceof CreateFolderOperation) {
+            onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
         }
     }
 
@@ -1322,6 +1189,30 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         }
     }
 
+    /**
+     * Updates the view associated to the activity after the finish of an operation trying create a new folder
+     * 
+     * @param operation     Creation operation performed.
+     * @param result        Result of the creation.
+     */
+    private void onCreateFolderOperationFinish(CreateFolderOperation operation, RemoteOperationResult result) {
+        if (result.isSuccess()) {
+            dismissDialog(DIALOG_SHORT_WAIT);
+            mFileList.listDirectory();
+            
+        } else {
+            dismissDialog(DIALOG_SHORT_WAIT);
+            try {
+                Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); 
+                msg.show();
+                    
+            } catch (NotFoundException e) {
+                Log_OC.e(TAG, "Error while trying to show fail message " , e);
+            }
+        }
+    }
+    
+    
     /**
      * Updates the view associated to the activity after the finish of an operation trying to rename a 
      * file. 
@@ -1430,7 +1321,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         //dialog.dismiss();
         if (dialog.getResult()) {
             String newDirectoryName = dialog.getNewFilename().trim();
-            Log.d(TAG, "'create directory' dialog dismissed with new name " + newDirectoryName);
+            Log_OC.d(TAG, "'create directory' dialog dismissed with new name " + newDirectoryName);
             if (newDirectoryName.length() > 0) {
                 String path;
                 if (mCurrentDir == null) {
@@ -1445,14 +1336,19 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
                 
                 // Create directory
                 path += newDirectoryName + OCFile.PATH_SEPARATOR;
-                Thread thread = new Thread(new DirectoryCreator(path,  AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), new Handler()));
-                thread.start();
+                RemoteOperation operation = new CreateFolderOperation(path, mCurrentDir.getFileId(), mStorageManager);
+                operation.execute(  AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), 
+                                    FileDisplayActivity.this, 
+                                    FileDisplayActivity.this, 
+                                    mHandler,
+                                    FileDisplayActivity.this);
                 
                 showDialog(DIALOG_SHORT_WAIT);
             }
         }
     }
-
+    
+    
     private void requestForDownload() {
         Account account = AccountUtils.getCurrentOwnCloudAccount(this);
         if (!mDownloaderBinder.isDownloading(account, mWaitingToPreview)) {

+ 3 - 14
src/com/owncloud/android/ui/activity/InstantUploadActivity.java

@@ -2,8 +2,8 @@
  *   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.
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
  *
  *   This program is distributed in the hope that it will be useful,
  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -26,7 +26,6 @@ import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Bundle;
-import android.util.Log;
 import android.util.SparseArray;
 import android.view.Gravity;
 import android.view.View;
@@ -59,16 +58,6 @@ import com.owncloud.android.utils.FileStorageUtils;
  * sub-menu underneath the 'Upload' menu-item
  * 
  * @author andomaex / Matthias Baumann
- * 
- *         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. (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 de/
  */
 public class InstantUploadActivity extends Activity {
 
@@ -363,7 +352,7 @@ public class InstantUploadActivity extends Activity {
 
             @Override
             public boolean onLongClick(View v) {
-                Log.d(LOG_TAG, message);
+                Log_OC.d(LOG_TAG, message);
                 Toast toast = Toast.makeText(InstantUploadActivity.this, getString(R.string.failed_upload_retry_text)
                         + message, Toast.LENGTH_LONG);
                 toast.show();

+ 3 - 3
src/com/owncloud/android/ui/activity/LandingActivity.java

@@ -17,7 +17,7 @@
 package com.owncloud.android.ui.activity;
 
 import com.actionbarsherlock.app.SherlockFragmentActivity;
-import com.owncloud.android.authenticator.AccountAuthenticator;
+import com.owncloud.android.authentication.AccountAuthenticator;
 import com.owncloud.android.ui.adapter.LandingScreenAdapter;
 
 import android.accounts.Account;
@@ -112,9 +112,9 @@ public class LandingActivity extends SherlockFragmentActivity implements
         dialog.dismiss();
         switch (which) {
         case DialogInterface.BUTTON_POSITIVE:
-            Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");
+            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);
             break;
         case DialogInterface.BUTTON_NEGATIVE:

+ 0 - 1
src/com/owncloud/android/ui/activity/UploadFilesActivity.java

@@ -25,7 +25,6 @@ import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Environment;
 import android.support.v4.app.DialogFragment;
-import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;

+ 0 - 1
src/com/owncloud/android/ui/dialog/SslValidatorDialog.java

@@ -31,7 +31,6 @@ import javax.security.auth.x500.X500Principal;
 import android.app.Dialog;
 import android.content.Context;
 import android.os.Bundle;
-import android.util.Log;
 import android.view.View;
 import android.view.Window;
 import android.widget.Button;

+ 0 - 1
src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java

@@ -22,7 +22,6 @@ import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.DialogInterface;
 import android.os.Bundle;
-import android.util.Log;
 
 import com.actionbarsherlock.app.SherlockDialogFragment;
 import com.owncloud.android.Log_OC;

+ 170 - 224
src/com/owncloud/android/ui/fragment/FileDetailFragment.java

@@ -19,24 +19,8 @@ package com.owncloud.android.ui.fragment;
 
 import java.io.File;
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.httpclient.methods.GetMethod;
-import org.apache.commons.httpclient.methods.PostMethod;
-import org.apache.commons.httpclient.methods.StringRequestEntity;
-import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
-import org.apache.http.HttpStatus;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.utils.URLEncodedUtils;
-import org.apache.http.message.BasicNameValuePair;
-import org.apache.http.protocol.HTTP;
-import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
-import org.json.JSONObject;
 
 import android.accounts.Account;
-import android.accounts.AccountManager;
-//import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
@@ -47,7 +31,6 @@ import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -60,42 +43,15 @@ import android.widget.ProgressBar;
 import android.widget.TextView;
 import android.widget.Toast;
 
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.BitmapFactory.Options;
-import android.graphics.Point;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Handler;
-import android.support.v4.app.DialogFragment;
-import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
-import android.view.Display;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.webkit.MimeTypeMap;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-
 import com.actionbarsherlock.app.SherlockFragment;
-import com.owncloud.android.AccountUtils;
 import com.owncloud.android.DisplayUtils;
 import com.owncloud.android.Log_OC;
-import com.owncloud.android.authenticator.AccountAuthenticator;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileObserverService;
 import com.owncloud.android.files.services.FileUploader;
 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.RemoteOperationResult;
@@ -108,15 +64,12 @@ import com.owncloud.android.ui.activity.FileDetailActivity;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
 import com.owncloud.android.ui.dialog.EditNameDialog;
 import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
-import com.owncloud.android.utils.OwnCloudVersion;
 
 import com.owncloud.android.R;
 
 import eu.alefzero.webdav.OnDatatransferProgressListener;
-import eu.alefzero.webdav.WebdavClient;
 import eu.alefzero.webdav.WebdavUtils;
 
-
 /**
  * This Fragment is used to display the details about a file.
  * 
@@ -163,7 +116,6 @@ public class FileDetailFragment extends SherlockFragment implements
         mProgressListener = null;
     }
     
-    
     /**
      * Creates a details fragment.
      * 
@@ -289,57 +241,58 @@ public class FileDetailFragment extends SherlockFragment implements
     }
 
     
-    @Override
-    public View getView() {
-        return super.getView() == null ? mView : super.getView();
-    }
-
-    @Override
-    public void onClick(View v) {
-        switch (v.getId()) {
-            case R.id.fdDownloadBtn: {
-                FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
-                FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
-                if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {
-                    downloaderBinder.cancel(mAccount, mFile);
-                    if (mFile.isDown()) {
-                        setButtonsForDown();
-                    } else {
-                        setButtonsForRemote();
-                    }
-
-                } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile)) {
-                    uploaderBinder.cancel(mAccount, mFile);
-                    if (!mFile.fileExists()) {
-                        // TODO make something better
-                        if (getActivity() instanceof FileDisplayActivity) {
-                            // double pane
-                            FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
-                            transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FTAG); // empty FileDetailFragment
-                            transaction.commit();
-                            mContainerActivity.onFileStateChanged();
-                        } else {
-                            getActivity().finish();
-                        }
-                        
-                    } else if (mFile.isDown()) {
-                        setButtonsForDown();
-                    } else {
-                        setButtonsForRemote();
-                    }
-                    
-                } else {
-                    mLastRemoteOperation = new SynchronizeFileOperation(mFile, null, mStorageManager, mAccount, true, false, getActivity());
-                    WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
-                    mLastRemoteOperation.execute(wc, this, mHandler);
-                
-                    // update ui 
-                    boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
-                    getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
-                    
-                }
-                break;
-            }
+    @Override
+    public View getView() {
+        return super.getView() == null ? mView : super.getView();
+    }
+
+    
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.fdDownloadBtn: {
+                FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
+                FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
+                if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {
+                    downloaderBinder.cancel(mAccount, mFile);
+                    if (mFile.isDown()) {
+                        setButtonsForDown();
+                    } else {
+                        setButtonsForRemote();
+                    }
+
+                } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile)) {
+                    uploaderBinder.cancel(mAccount, mFile);
+                    if (!mFile.fileExists()) {
+                        // TODO make something better
+                        if (getActivity() instanceof FileDisplayActivity) {
+                            // double pane
+                            FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
+                            transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FTAG); // empty FileDetailFragment
+                            transaction.commit();
+                            mContainerActivity.onFileStateChanged();
+                        } else {
+                            getActivity().finish();
+                        }
+                        
+                    } else if (mFile.isDown()) {
+                        setButtonsForDown();
+                    } else {
+                        setButtonsForRemote();
+                    }
+                    
+                } else {
+                    mLastRemoteOperation = new SynchronizeFileOperation(mFile, null, mStorageManager, mAccount, true, false, getActivity());
+                    mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
+                
+                    // update ui 
+                    boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
+                    getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
+                    setButtonsForTransferring(); // disable button immediately, although the synchronization does not result in a file transference
+                    
+                }
+                break;
+            }
             case R.id.fdKeepInSync: {
                 CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync);
                 mFile.setKeepInSync(cb.isChecked());
@@ -389,13 +342,8 @@ public class FileDetailFragment extends SherlockFragment implements
                 Log_OC.e(TAG, "Incorrect view clicked!");
         }
         
-        /* else if (v.getId() == R.id.fdShareBtn) {
-            Thread t = new Thread(new ShareRunnable(mFile.getRemotePath()));
-            t.start();
-        }*/
-    }
-    
-    
+    }
+    
     /**
      * Opens mFile.
      */
@@ -410,7 +358,7 @@ public class FileDetailFragment extends SherlockFragment implements
             startActivity(i);
             
         } catch (Throwable t) {
-            Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
+            Log_OC.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
             boolean toastIt = true; 
             String mimeType = "";
             try {
@@ -429,13 +377,13 @@ public class FileDetailFragment extends SherlockFragment implements
                 }
                 
             } catch (IndexOutOfBoundsException e) {
-                Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
+                Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
                 
             } catch (ActivityNotFoundException e) {
-                Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
+                Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
                 
             } catch (Throwable th) {
-                Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);
+                Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
                 
             } finally {
                 if (toastIt) {
@@ -446,7 +394,6 @@ public class FileDetailFragment extends SherlockFragment implements
         }
     }
 
-
     @Override
     public void onConfirmation(String callerTag) {
         if (callerTag.equals(FTAG_CONFIRMATION)) {
@@ -454,8 +401,7 @@ public class FileDetailFragment extends SherlockFragment implements
                 mLastRemoteOperation = new RemoveFileOperation( mFile, 
                                                                 true, 
                                                                 mStorageManager);
-                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
-                mLastRemoteOperation.execute(wc, this, mHandler);
+                mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
                 
                 boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
                 getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
@@ -476,7 +422,7 @@ public class FileDetailFragment extends SherlockFragment implements
     
     @Override
     public void onCancel(String callerTag) {
-        Log.d(TAG, "REMOVAL CANCELED");
+        Log_OC.d(TAG, "REMOVAL CANCELED");
     }
     
     
@@ -567,7 +513,6 @@ public class FileDetailFragment extends SherlockFragment implements
         getView().invalidate();
     }
     
-    
     /**
      * Checks if the fragment is ready to show details of a OCFile
      *  
@@ -769,120 +714,15 @@ public class FileDetailFragment extends SherlockFragment implements
     }
     
 
-    // this is a temporary class for sharing purposes, it need to be replaced in transfer service
-    @SuppressWarnings("unused")
-    private class ShareRunnable implements Runnable {
-        private String mPath;
-
-        public ShareRunnable(String path) {
-            mPath = path;
-        }
-        
-        public void run() {
-            AccountManager am = AccountManager.get(getActivity());
-            Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());
-            OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION));
-            String url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + AccountUtils.getWebdavPath(ocv);
-
-            Log.d("share", "sharing for version " + ocv.toString());
-
-            if (ocv.compareTo(new OwnCloudVersion(0x040000)) >= 0) {
-                String APPS_PATH = "/apps/files_sharing/";
-                String SHARE_PATH = "ajax/share.php";
-
-                String SHARED_PATH = "/apps/files_sharing/get.php?token=";
-                
-                final String WEBDAV_SCRIPT = "webdav.php";
-                final String WEBDAV_FILES_LOCATION = "/files/";
-                
-                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(account, getActivity().getApplicationContext());
-                HttpConnectionManagerParams params = new HttpConnectionManagerParams();
-                params.setMaxConnectionsPerHost(wc.getHostConfiguration(), 5);
-
-                //wc.getParams().setParameter("http.protocol.single-cookie-header", true);
-                //wc.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
-
-                PostMethod post = new PostMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + APPS_PATH + SHARE_PATH);
-
-                post.addRequestHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8" );
-                post.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));
-                List<NameValuePair> formparams = new ArrayList<NameValuePair>();
-                Log.d("share", mPath+"");
-                formparams.add(new BasicNameValuePair("sources",mPath));
-                formparams.add(new BasicNameValuePair("uid_shared_with", "public"));
-                formparams.add(new BasicNameValuePair("permissions", "0"));
-                post.setRequestEntity(new StringRequestEntity(URLEncodedUtils.format(formparams, HTTP.UTF_8)));
-
-                int status;
-                try {
-                    PropFindMethod find = new PropFindMethod(url+"/");
-                    find.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));
-                    Log.d("sharer", ""+ url+"/");
-                    
-                    for (org.apache.commons.httpclient.Header a : find.getRequestHeaders()) {
-                        Log.d("sharer-h", a.getName() + ":"+a.getValue());
-                    }
-                    
-                    int status2 = wc.executeMethod(find);
-
-                    Log.d("sharer", "propstatus "+status2);
-                    
-                    GetMethod get = new GetMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + "/");
-                    get.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));
-                    
-                    status2 = wc.executeMethod(get);
-
-                    Log.d("sharer", "getstatus "+status2);
-                    Log.d("sharer", "" + get.getResponseBodyAsString());
-                    
-                    for (org.apache.commons.httpclient.Header a : get.getResponseHeaders()) {
-                        Log.d("sharer", a.getName() + ":"+a.getValue());
-                    }
-
-                    status = wc.executeMethod(post);
-                    for (org.apache.commons.httpclient.Header a : post.getRequestHeaders()) {
-                        Log.d("sharer-h", a.getName() + ":"+a.getValue());
-                    }
-                    for (org.apache.commons.httpclient.Header a : post.getResponseHeaders()) {
-                        Log.d("sharer", a.getName() + ":"+a.getValue());
-                    }
-                    String resp = post.getResponseBodyAsString();
-                    Log.d("share", ""+post.getURI().toString());
-                    Log.d("share", "returned status " + status);
-                    Log.d("share", " " +resp);
-                    
-                    if(status != HttpStatus.SC_OK ||resp == null || resp.equals("") || resp.startsWith("false")) {
-                        return;
-                     }
-
-                    JSONObject jsonObject = new JSONObject (resp);
-                    String jsonStatus = jsonObject.getString("status");
-                    if(!jsonStatus.equals("success")) throw new Exception("Error while sharing file status != success");
-                    
-                    String token = jsonObject.getString("data");
-                    String uri = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + SHARED_PATH + token; 
-                    Log.d("Actions:shareFile ok", "url: " + uri);   
-                    
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-                
-            } else if (ocv.compareTo(new OwnCloudVersion(0x030000)) >= 0) {
-                
-            }
-        }
-    }
-    
     public void onDismiss(EditNameDialog dialog) {
         if (dialog.getResult()) {
             String newFilename = dialog.getNewFilename();
-            Log.d(TAG, "name edit dialog dismissed with new name " + newFilename);
+            Log_OC.d(TAG, "name edit dialog dismissed with new name " + newFilename);
             mLastRemoteOperation = new RenameFileOperation( mFile, 
                                                             mAccount, 
                                                             newFilename, 
                                                             new FileDataStorageManager(mAccount, getActivity().getContentResolver()));
-            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
-            mLastRemoteOperation.execute(wc, this, mHandler);
+            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
             boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
             getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
         }
@@ -998,7 +838,7 @@ public class FileDetailFragment extends SherlockFragment implements
         }
     }
     
-    
+
     public void listenForTransferProgress() {
         if (mProgressListener != null) {
             if (mContainerActivity.getFileDownloaderBinder() != null) {
@@ -1057,4 +897,110 @@ public class FileDetailFragment extends SherlockFragment implements
 
     };
 
-}
+    /*
+    // this is a temporary class for sharing purposes, it need to be replaced in transfer service
+    @SuppressWarnings("unused")
+    private class ShareRunnable implements Runnable {
+        private String mPath;
+
+        public ShareRunnable(String path) {
+            mPath = path;
+        }
+        
+        public void run() {
+            AccountManager am = AccountManager.get(getActivity());
+            Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());
+            OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION));
+            String url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + AccountUtils.getWebdavPath(ocv);
+
+            Log_OC.d("share", "sharing for version " + ocv.toString());
+
+            if (ocv.compareTo(new OwnCloudVersion(0x040000)) >= 0) {
+                String APPS_PATH = "/apps/files_sharing/";
+                String SHARE_PATH = "ajax/share.php";
+
+                String SHARED_PATH = "/apps/files_sharing/get.php?token=";
+                
+                final String WEBDAV_SCRIPT = "webdav.php";
+                final String WEBDAV_FILES_LOCATION = "/files/";
+                
+                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(account, getActivity().getApplicationContext());
+                HttpConnectionManagerParams params = new HttpConnectionManagerParams();
+                params.setMaxConnectionsPerHost(wc.getHostConfiguration(), 5);
+
+                //wc.getParams().setParameter("http.protocol.single-cookie-header", true);
+                //wc.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
+
+                PostMethod post = new PostMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + APPS_PATH + SHARE_PATH);
+
+                post.addRequestHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8" );
+                post.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));
+                List<NameValuePair> formparams = new ArrayList<NameValuePair>();
+                Log_OC.d("share", mPath+"");
+                formparams.add(new BasicNameValuePair("sources",mPath));
+                formparams.add(new BasicNameValuePair("uid_shared_with", "public"));
+                formparams.add(new BasicNameValuePair("permissions", "0"));
+                post.setRequestEntity(new StringRequestEntity(URLEncodedUtils.format(formparams, HTTP.UTF_8)));
+
+                int status;
+                try {
+                    PropFindMethod find = new PropFindMethod(url+"/");
+                    find.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));
+                    Log_OC.d("sharer", ""+ url+"/");
+                    
+                    for (org.apache.commons.httpclient.Header a : find.getRequestHeaders()) {
+                        Log_OC.d("sharer-h", a.getName() + ":"+a.getValue());
+                    }
+                    
+                    int status2 = wc.executeMethod(find);
+
+                    Log_OC.d("sharer", "propstatus "+status2);
+                    
+                    GetMethod get = new GetMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + "/");
+                    get.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));
+                    
+                    status2 = wc.executeMethod(get);
+
+                    Log_OC.d("sharer", "getstatus "+status2);
+                    Log_OC.d("sharer", "" + get.getResponseBodyAsString());
+                    
+                    for (org.apache.commons.httpclient.Header a : get.getResponseHeaders()) {
+                        Log_OC.d("sharer", a.getName() + ":"+a.getValue());
+                    }
+
+                    status = wc.executeMethod(post);
+                    for (org.apache.commons.httpclient.Header a : post.getRequestHeaders()) {
+                        Log_OC.d("sharer-h", a.getName() + ":"+a.getValue());
+                    }
+                    for (org.apache.commons.httpclient.Header a : post.getResponseHeaders()) {
+                        Log_OC.d("sharer", a.getName() + ":"+a.getValue());
+                    }
+                    String resp = post.getResponseBodyAsString();
+                    Log_OC.d("share", ""+post.getURI().toString());
+                    Log_OC.d("share", "returned status " + status);
+                    Log_OC.d("share", " " +resp);
+                    
+                    if(status != HttpStatus.SC_OK ||resp == null || resp.equals("") || resp.startsWith("false")) {
+                        return;
+                     }
+
+                    JSONObject jsonObject = new JSONObject (resp);
+                    String jsonStatus = jsonObject.getString("status");
+                    if(!jsonStatus.equals("success")) throw new Exception("Error while sharing file status != success");
+                    
+                    String token = jsonObject.getString("data");
+                    String uri = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + SHARED_PATH + token; 
+                    Log_OC.d("Actions:shareFile ok", "url: " + uri);   
+                    
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+                
+            } else if (ocv.compareTo(new OwnCloudVersion(0x030000)) >= 0) {
+                
+            }
+        }
+    }
+    */
+    
+}

+ 0 - 1
src/com/owncloud/android/ui/fragment/LocalFileListFragment.java

@@ -25,7 +25,6 @@ import com.owncloud.android.ui.adapter.LocalFileListAdapter;
 import android.app.Activity;
 import android.os.Bundle;
 import android.os.Environment;
-import android.util.Log;
 import android.util.SparseBooleanArray;
 import android.view.LayoutInflater;
 import android.view.View;

+ 3 - 9
src/com/owncloud/android/ui/fragment/OCFileListFragment.java

@@ -28,7 +28,6 @@ import com.owncloud.android.datamodel.DataStorageManager;
 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;
@@ -42,7 +41,6 @@ import com.owncloud.android.ui.dialog.EditNameDialog;
 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;
@@ -52,7 +50,6 @@ import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
-import android.util.Log;
 import android.view.ContextMenu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -317,8 +314,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
             case R.id.action_download_file: {
                 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;
             }
@@ -484,8 +480,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
                                                                 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);
         }
     }
@@ -498,8 +493,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
                 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);
             }

+ 4 - 4
src/com/owncloud/android/ui/preview/FileDownloadFragment.java

@@ -3,8 +3,8 @@
  *   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.
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
  *
  *   This program is distributed in the hope that it will be useful,
  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -23,7 +23,6 @@ import android.accounts.Account;
 import android.app.Activity;
 import android.os.Bundle;
 import android.support.v4.app.FragmentStatePagerAdapter;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -38,6 +37,7 @@ import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.ui.fragment.FileFragment;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 
 import eu.alefzero.webdav.OnDatatransferProgressListener;
@@ -239,7 +239,7 @@ public class FileDownloadFragment extends SherlockFragment implements OnClickLis
                 break;
             }
             default:
-                Log.e(TAG, "Incorrect view clicked!");
+                Log_OC.e(TAG, "Incorrect view clicked!");
         }
     }
 

+ 7 - 10
src/com/owncloud/android/ui/preview/PreviewImageActivity.java

@@ -16,8 +16,6 @@
  */
 package com.owncloud.android.ui.preview;
 
-import org.apache.commons.httpclient.methods.PostMethod;
-
 import android.accounts.Account;
 import android.app.Dialog;
 import android.app.ProgressDialog;
@@ -29,9 +27,7 @@ import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.support.v4.app.Fragment;
 import android.support.v4.view.ViewPager;
-import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnTouchListener;
@@ -52,6 +48,7 @@ import com.owncloud.android.ui.fragment.FileDetailFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 
 /**
@@ -170,12 +167,12 @@ public class PreviewImageActivity extends SherlockFragmentActivity implements Fi
                 mDownloaderBinder = (FileDownloaderBinder) service;
                 if (mRequestWaitingForBinder) {
                     mRequestWaitingForBinder = false;
-                    Log.d(TAG, "Simulating reselection of current page after connection of download binder");
+                    Log_OC.d(TAG, "Simulating reselection of current page after connection of download binder");
                     onPageSelected(mViewPager.getCurrentItem());
                 }
                     
             } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) {
-                Log.d(TAG, "Upload service connected");
+                Log_OC.d(TAG, "Upload service connected");
                 mUploaderBinder = (FileUploaderBinder) service;
             } else {
                 return;
@@ -186,10 +183,10 @@ public class PreviewImageActivity extends SherlockFragmentActivity implements Fi
         @Override
         public void onServiceDisconnected(ComponentName component) {
             if (component.equals(new ComponentName(PreviewImageActivity.this, FileDownloader.class))) {
-                Log.d(TAG, "Download service suddenly disconnected");
+                Log_OC.d(TAG, "Download service suddenly disconnected");
                 mDownloaderBinder = null;
             } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) {
-                Log.d(TAG, "Upload service suddenly disconnected");
+                Log_OC.d(TAG, "Upload service suddenly disconnected");
                 mUploaderBinder = null;
             }
         }
@@ -328,7 +325,7 @@ public class PreviewImageActivity extends SherlockFragmentActivity implements Fi
     
     private void requestForDownload(OCFile file) {
         if (mDownloaderBinder == null) {
-            Log.d(TAG, "requestForDownload called without binder to download service");
+            Log_OC.d(TAG, "requestForDownload called without binder to download service");
             
         } else if (!mDownloaderBinder.isDownloading(mAccount, file)) {
             Intent i = new Intent(this, FileDownloader.class);
@@ -413,7 +410,7 @@ public class PreviewImageActivity extends SherlockFragmentActivity implements Fi
                     mPreviewImagePagerAdapter.notifyDataSetChanged();   // will trigger the creation of new fragments
                     
                 } else {
-                    Log.d(TAG, "Download finished, but the fragment is offscreen");
+                    Log_OC.d(TAG, "Download finished, but the fragment is offscreen");
                 }
                 
             }

+ 11 - 14
src/com/owncloud/android/ui/preview/PreviewImageFragment.java

@@ -36,7 +36,6 @@ import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v4.app.FragmentStatePagerAdapter;
-import android.util.Log;
 import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -54,7 +53,6 @@ import com.actionbarsherlock.view.MenuInflater;
 import com.actionbarsherlock.view.MenuItem;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.network.OwnCloudClientUtils;
 import com.owncloud.android.operations.OnRemoteOperationListener;
 import com.owncloud.android.operations.RemoteOperation;
 import com.owncloud.android.operations.RemoteOperationResult;
@@ -62,8 +60,8 @@ import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.ui.fragment.ConfirmationDialogFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
-import eu.alefzero.webdav.WebdavClient;
 import eu.alefzero.webdav.WebdavUtils;
 
 
@@ -339,7 +337,7 @@ public class PreviewImageFragment extends SherlockFragment implements   FileFrag
             startActivity(i);
             
         } catch (Throwable t) {
-            Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
+            Log_OC.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
             boolean toastIt = true; 
             String mimeType = "";
             try {
@@ -358,13 +356,13 @@ public class PreviewImageFragment extends SherlockFragment implements   FileFrag
                 }
                 
             } catch (IndexOutOfBoundsException e) {
-                Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
+                Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
                 
             } catch (ActivityNotFoundException e) {
-                Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
+                Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
                 
             } catch (Throwable th) {
-                Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);
+                Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
                 
             } finally {
                 if (toastIt) {
@@ -404,8 +402,7 @@ public class PreviewImageFragment extends SherlockFragment implements   FileFrag
             mLastRemoteOperation = new RemoveFileOperation( mFile,      // TODO we need to review the interface with RemoteOperations, and use OCFile IDs instead of OCFile objects as parameters
                                                             true, 
                                                             mStorageManager);
-            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
-            mLastRemoteOperation.execute(wc, this, mHandler);
+            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
             
             getActivity().showDialog(PreviewImageActivity.DIALOG_SHORT_WAIT);
         }
@@ -557,24 +554,24 @@ public class PreviewImageFragment extends SherlockFragment implements   FileFrag
                 // really load the bitmap
                 options.inJustDecodeBounds = false; // the next decodeFile call will be real
                 result = BitmapFactory.decodeFile(storagePath, options);
-                //Log.d(TAG, "Image loaded - width: " + options.outWidth + ", loaded height: " + options.outHeight);
+                //Log_OC.d(TAG, "Image loaded - width: " + options.outWidth + ", loaded height: " + options.outHeight);
 
                 if (result == null) {
                     mErrorMessageId = R.string.preview_image_error_unknown_format;
-                    Log.e(TAG, "File could not be loaded as a bitmap: " + storagePath);
+                    Log_OC.e(TAG, "File could not be loaded as a bitmap: " + storagePath);
                 }
                 
             } catch (OutOfMemoryError e) {
                 mErrorMessageId = R.string.preview_image_error_unknown_format;
-                Log.e(TAG, "Out of memory occured for file " + storagePath, e);
+                Log_OC.e(TAG, "Out of memory occured for file " + storagePath, e);
                     
             } catch (NoSuchFieldError e) {
                 mErrorMessageId = R.string.common_error_unknown;
-                Log.e(TAG, "Error from access to unexisting field despite protection; file " + storagePath, e);
+                Log_OC.e(TAG, "Error from access to unexisting field despite protection; file " + storagePath, e);
                     
             } catch (Throwable t) {
                 mErrorMessageId = R.string.common_error_unknown;
-                Log.e(TAG, "Unexpected error loading " + mFile.getStoragePath(), t);
+                Log_OC.e(TAG, "Unexpected error loading " + mFile.getStoragePath(), t);
                 
             }
             return result;

+ 0 - 8
src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java

@@ -16,7 +16,6 @@
  */
 package com.owncloud.android.ui.preview;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -24,16 +23,9 @@ import java.util.Set;
 import java.util.Vector;
 
 import android.accounts.Account;
-import android.os.Bundle;
-import android.os.Parcelable;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentStatePagerAdapter;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.util.Log;
-import android.view.View;
 import android.view.ViewGroup;
 
 import com.owncloud.android.datamodel.DataStorageManager;

+ 15 - 18
src/com/owncloud/android/ui/preview/PreviewMediaFragment.java

@@ -39,7 +39,6 @@ import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -59,7 +58,6 @@ import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.media.MediaControlView;
 import com.owncloud.android.media.MediaService;
 import com.owncloud.android.media.MediaServiceBinder;
-import com.owncloud.android.network.OwnCloudClientUtils;
 import com.owncloud.android.operations.OnRemoteOperationListener;
 import com.owncloud.android.operations.RemoteOperation;
 import com.owncloud.android.operations.RemoteOperationResult;
@@ -70,8 +68,8 @@ import com.owncloud.android.ui.fragment.ConfirmationDialogFragment;
 import com.owncloud.android.ui.fragment.FileDetailFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
-import eu.alefzero.webdav.WebdavClient;
 import eu.alefzero.webdav.WebdavUtils;
 
 /**
@@ -354,7 +352,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
          */
         @Override
         public void onPrepared(MediaPlayer vp) {
-            Log.e(TAG, "onPrepared");
+            Log_OC.e(TAG, "onPrepared");
             mVideoPreview.seekTo(mSavedPlaybackPosition);
             if (mAutoplay) { 
                 mVideoPreview.start();
@@ -373,7 +371,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
          */
         @Override
         public void onCompletion(MediaPlayer  mp) {
-            Log.e(TAG, "completed");
+            Log_OC.e(TAG, "completed");
             if (mp != null) {
                 mVideoPreview.seekTo(0);
                 // next lines are necessary to work around undesired video loops
@@ -428,7 +426,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
         super.onStop();
         
         if (mMediaServiceConnection != null) {
-            Log.d(TAG, "Unbinding from MediaService ...");
+            Log_OC.d(TAG, "Unbinding from MediaService ...");
             if (mMediaServiceBinder != null && mMediaController != null) {
                 mMediaServiceBinder.unregisterMediaController(mMediaController);
             }
@@ -471,7 +469,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
 
     private void playAudio() {
         if (!mMediaServiceBinder.isPlaying(mFile)) {
-            Log.d(TAG, "starting playback of " + mFile.getStoragePath());
+            Log_OC.d(TAG, "starting playback of " + mFile.getStoragePath());
             mMediaServiceBinder.start(mAccount, mFile, mAutoplay, mSavedPlaybackPosition);
             
         } else {
@@ -484,7 +482,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
 
 
     private void bindMediaService() {
-        Log.d(TAG, "Binding to MediaService...");
+        Log_OC.d(TAG, "Binding to MediaService...");
         if (mMediaServiceConnection == null) {
             mMediaServiceConnection = new MediaServiceConnection();
         }
@@ -501,16 +499,16 @@ public class PreviewMediaFragment extends SherlockFragment implements
         @Override
         public void onServiceConnected(ComponentName component, IBinder service) {
             if (component.equals(new ComponentName(getActivity(), MediaService.class))) {
-                Log.d(TAG, "Media service connected");
+                Log_OC.d(TAG, "Media service connected");
                 mMediaServiceBinder = (MediaServiceBinder) service;
                 if (mMediaServiceBinder != null) {
                     prepareMediaController();
                     playAudio();    // do not wait for the touch of nobody to play audio
                     
-                    Log.d(TAG, "Successfully bound to MediaService, MediaController ready");
+                    Log_OC.d(TAG, "Successfully bound to MediaService, MediaController ready");
                     
                 } else {
-                    Log.e(TAG, "Unexpected response from MediaService while binding");
+                    Log_OC.e(TAG, "Unexpected response from MediaService while binding");
                 }
             }
         }
@@ -527,7 +525,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
         @Override
         public void onServiceDisconnected(ComponentName component) {
             if (component.equals(new ComponentName(getActivity(), MediaService.class))) {
-                Log.e(TAG, "Media service suddenly disconnected");
+                Log_OC.e(TAG, "Media service suddenly disconnected");
                 if (mMediaController != null) {
                     mMediaController.setMediaPlayer(null);
                 } else {
@@ -559,7 +557,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
             startActivity(i);
             
         } catch (Throwable t) {
-            Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
+            Log_OC.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
             boolean toastIt = true; 
             String mimeType = "";
             try {
@@ -578,13 +576,13 @@ public class PreviewMediaFragment extends SherlockFragment implements
                 }
                 
             } catch (IndexOutOfBoundsException e) {
-                Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
+                Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
                 
             } catch (ActivityNotFoundException e) {
-                Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
+                Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
                 
             } catch (Throwable th) {
-                Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);
+                Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
                 
             } finally {
                 if (toastIt) {
@@ -624,8 +622,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
             mLastRemoteOperation = new RemoveFileOperation( mFile,      // TODO we need to review the interface with RemoteOperations, and use OCFile IDs instead of OCFile objects as parameters
                                                             true, 
                                                             mStorageManager);
-            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
-            mLastRemoteOperation.execute(wc, this, mHandler);
+            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
             
             boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
             getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);

+ 11 - 11
src/com/owncloud/android/ui/preview/PreviewVideoActivity.java

@@ -28,12 +28,12 @@ import android.media.MediaPlayer.OnErrorListener;
 import android.media.MediaPlayer.OnPreparedListener;
 import android.net.Uri;
 import android.os.Bundle;
-import android.util.Log;
 import android.view.MotionEvent;
 import android.widget.MediaController;
 import android.widget.VideoView;
 
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.media.MediaService;
@@ -84,7 +84,7 @@ public class PreviewVideoActivity extends Activity implements OnCompletionListen
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        Log.e(TAG, "ACTIVITY\t\tonCreate");
+        Log_OC.e(TAG, "ACTIVITY\t\tonCreate");
         
         setContentView(R.layout.video_layout);
     
@@ -143,7 +143,7 @@ public class PreviewVideoActivity extends Activity implements OnCompletionListen
     @Override
     public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
-        Log.e(TAG, "ACTIVITY\t\tonSaveInstanceState");
+        Log_OC.e(TAG, "ACTIVITY\t\tonSaveInstanceState");
         outState.putParcelable(PreviewVideoActivity.EXTRA_FILE, mFile);
         outState.putParcelable(PreviewVideoActivity.EXTRA_ACCOUNT, mAccount);
         outState.putInt(PreviewVideoActivity.EXTRA_START_POSITION, mVideoPlayer.getCurrentPosition());
@@ -153,7 +153,7 @@ public class PreviewVideoActivity extends Activity implements OnCompletionListen
     
     @Override
     public void onBackPressed() {
-        Log.e(TAG, "ACTIVTIY\t\tonBackPressed");
+        Log_OC.e(TAG, "ACTIVTIY\t\tonBackPressed");
         Intent i = new Intent();
         i.putExtra(EXTRA_AUTOPLAY, mVideoPlayer.isPlaying());
         i.putExtra(EXTRA_START_POSITION, mVideoPlayer.getCurrentPosition());
@@ -165,33 +165,33 @@ public class PreviewVideoActivity extends Activity implements OnCompletionListen
     @Override
     public void onResume() {
         super.onResume();
-        Log.e(TAG, "ACTIVTIY\t\tonResume");
+        Log_OC.e(TAG, "ACTIVTIY\t\tonResume");
     }
 
     
     @Override
     public void onStart() {
         super.onStart();
-        Log.e(TAG, "ACTIVTIY\t\tonStart");
+        Log_OC.e(TAG, "ACTIVTIY\t\tonStart");
     }
     
     @Override
     public void onDestroy() {
         super.onDestroy();
-        Log.e(TAG, "ACTIVITY\t\tonDestroy");
+        Log_OC.e(TAG, "ACTIVITY\t\tonDestroy");
     }
     
     @Override
     public void onStop() {
         super.onStop();
-        Log.e(TAG, "ACTIVTIY\t\tonStop");
+        Log_OC.e(TAG, "ACTIVTIY\t\tonStop");
     }
     
     
     @Override
     public void onPause() {
         super.onPause();
-        Log.e(TAG, "ACTIVTIY\t\tonPause");
+        Log_OC.e(TAG, "ACTIVTIY\t\tonPause");
     }
     
     
@@ -204,7 +204,7 @@ public class PreviewVideoActivity extends Activity implements OnCompletionListen
      */
     @Override
     public void onPrepared(MediaPlayer mp) {
-        Log.e(TAG, "ACTIVITY\t\tonPrepare");
+        Log_OC.e(TAG, "ACTIVITY\t\tonPrepare");
         mVideoPlayer.seekTo(mSavedPlaybackPosition);
         if (mAutoplay) { 
             mVideoPlayer.start();
@@ -235,7 +235,7 @@ public class PreviewVideoActivity extends Activity implements OnCompletionListen
      */
     @Override
     public boolean onError(MediaPlayer mp, int what, int extra) {
-        Log.e(TAG, "Error in video playback, what = " + what + ", extra = " + extra);
+        Log_OC.e(TAG, "Error in video playback, what = " + what + ", extra = " + extra);
         
         if (mMediaController != null) {
             mMediaController.hide();

+ 0 - 1
src/com/owncloud/android/utils/FileStorageUtils.java

@@ -24,7 +24,6 @@ import android.content.Context;
 import android.net.Uri;
 import android.os.Environment;
 import android.os.StatFs;
-import android.util.Log;
 
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;

+ 33 - 184
src/eu/alefzero/webdav/WebdavClient.java

@@ -15,6 +15,7 @@
  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
+
 package eu.alefzero.webdav;
 
 import java.io.BufferedInputStream;
@@ -22,14 +23,20 @@ import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.HostConfiguration;
 import org.apache.commons.httpclient.HttpClient;
 import org.apache.commons.httpclient.HttpConnectionManager;
 import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.HttpMethod;
 import org.apache.commons.httpclient.HttpMethodBase;
+import org.apache.commons.httpclient.HttpState;
 import org.apache.commons.httpclient.HttpVersion;
 import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.auth.AuthPolicy;
 import org.apache.commons.httpclient.auth.AuthScope;
 import org.apache.commons.httpclient.methods.GetMethod;
 import org.apache.commons.httpclient.methods.HeadMethod;
@@ -39,12 +46,13 @@ import org.apache.http.HttpStatus;
 import org.apache.http.params.CoreProtocolPNames;
 import org.apache.jackrabbit.webdav.client.methods.DavMethod;
 import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
-import org.apache.jackrabbit.webdav.client.methods.MkColMethod;
 
 import com.owncloud.android.Log_OC;
 
+import com.owncloud.android.network.BearerAuthScheme;
+import com.owncloud.android.network.BearerCredentials;
+
 import android.net.Uri;
-import android.util.Log;
 
 public class WebdavClient extends HttpClient {
     private Uri mUri;
@@ -65,176 +73,32 @@ public class WebdavClient extends HttpClient {
         getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
     }
 
-    public void setCredentials(String username, String password) {
-        getParams().setAuthenticationPreemptive(true);
-        getState().setCredentials(AuthScope.ANY,
-                getCredentials(username, password));
-    }
-
-    private Credentials getCredentials(String username, String password) {
-        if (mCredentials == null)
-            mCredentials = new UsernamePasswordCredentials(username, password);
-        return mCredentials;
-    }
-    
-    /**
-     * Downloads a file in remoteFilepath to the local targetPath.
-     * 
-     * @param remoteFilepath    Path to the file in the remote server, URL DECODED. 
-     * @param targetFile        Local path to save the downloaded file.
-     * @return                  'True' when the file is successfully downloaded.
-     */
-    public boolean downloadFile(String remoteFilePath, File targetFile) {
-        boolean ret = false;
-        GetMethod get = new GetMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath));
-
-        try {
-            int status = executeMethod(get);
-            if (status == HttpStatus.SC_OK) {
-                targetFile.createNewFile();
-                BufferedInputStream bis = new BufferedInputStream(
-                        get.getResponseBodyAsStream());
-                FileOutputStream fos = new FileOutputStream(targetFile);
-
-                byte[] bytes = new byte[4096];
-                int readResult;
-                while ((readResult = bis.read(bytes)) != -1) {
-                    if (mDataTransferListener != null)
-                        mDataTransferListener.onTransferProgress(readResult);
-                    fos.write(bytes, 0, readResult);
-                }
-                fos.close();
-                ret = true;
-            } else {
-                exhaustResponse(get.getResponseBodyAsStream());
-            }
-            Log_OC.e(TAG, "Download of " + remoteFilePath + " to " + targetFile + " finished with HTTP status " + status + (!ret?"(FAIL)":""));
-            
-        } catch (Exception e) {
-            logException(e, "dowloading " + remoteFilePath);
-            
-        } finally {
-            if (!ret && targetFile.exists()) {
-                targetFile.delete();
-            }
-            get.releaseConnection();    // let the connection available for other methods
-        }
-        return ret;
-    }
-    
-    /**
-     * Deletes a remote file via webdav
-     * @param remoteFilePath       Remote file path of the file to delete, in URL DECODED format.
-     * @return
-     */
-    public boolean deleteFile(String remoteFilePath) {
-        boolean ret = false;
-        DavMethod delete = new DeleteMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath));
-        try {
-            int status = executeMethod(delete);
-            ret = (status == HttpStatus.SC_OK || status == HttpStatus.SC_ACCEPTED || status == HttpStatus.SC_NO_CONTENT);
-            exhaustResponse(delete.getResponseBodyAsStream());
-            
-            Log_OC.e(TAG, "DELETE of " + remoteFilePath + " finished with HTTP status " + status +  (!ret?"(FAIL)":""));
-            
-        } catch (Exception e) {
-            logException(e, "deleting " + remoteFilePath);
-            
-        } finally {
-            delete.releaseConnection();    // let the connection available for other methods
-        }
-        return ret;
-    }
-
-    
-    public void setDataTransferProgressListener(OnDatatransferProgressListener listener) {
-        mDataTransferListener = listener;
-    }
-    
-    /**
-     * Creates or update a file in the remote server with the contents of a local file.
-     * 
-     * @param localFile         Path to the local file to upload.
-     * @param remoteTarget      Remote path to the file to create or update, URL DECODED
-     * @param contentType       MIME type of the file.
-     * @return                  Status HTTP code returned by the server.
-     * @throws IOException      When a transport error that could not be recovered occurred while uploading the file to the server.
-     * @throws HttpException    When a violation of the HTTP protocol occurred. 
-     */
-    public int putFile(String localFile, String remoteTarget, String contentType) throws HttpException, IOException {
-        int status = -1;
-        PutMethod put = new PutMethod(mUri.toString() + WebdavUtils.encodePath(remoteTarget));
+    public void setBearerCredentials(String accessToken) {
+        AuthPolicy.registerAuthScheme(BearerAuthScheme.AUTH_POLICY, BearerAuthScheme.class);
         
-        try {
-            File f = new File(localFile);
-            FileRequestEntity entity = new FileRequestEntity(f, contentType);
-            entity.addDatatransferProgressListener(mDataTransferListener);
-            put.setRequestEntity(entity);
-            status = executeMethod(put);
-            
-            exhaustResponse(put.getResponseBodyAsStream());
-            
-        } finally {
-            put.releaseConnection();    // let the connection available for other methods
-        }
-        return status;
-    }
-    
-    /**
-     * Tries to log in to the current URI, with the current credentials
-     * 
-     * @return A {@link HttpStatus}-Code of the result. SC_OK is good.
-     */
-    public int tryToLogin() {
-        int status = 0;
-        HeadMethod head = new HeadMethod(mUri.toString());
-        try {
-            status = executeMethod(head);
-            boolean result = status == HttpStatus.SC_OK;
-            Log_OC.d(TAG, "HEAD for " + mUri + " finished with HTTP status " + status + (!result?"(FAIL)":""));
-            exhaustResponse(head.getResponseBodyAsStream());
-            
-        } catch (Exception e) {
-            logException(e, "trying to login at " + mUri.toString());
-            
-        } finally {
-            head.releaseConnection();
-        }
-        return status;
+        List<String> authPrefs = new ArrayList<String>(1);
+        authPrefs.add(BearerAuthScheme.AUTH_POLICY);
+        getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);        
+        
+        mCredentials = new BearerCredentials(accessToken);
+        getState().setCredentials(AuthScope.ANY, mCredentials);
     }
 
-    /**
-     * Creates a remote directory with the received path.
-     * 
-     * @param path      Path of the directory to create, URL DECODED
-     * @return          'True' when the directory is successfully created
-     */
-    public boolean createDirectory(String path) {
-        boolean result = false;
-        int status = -1;
-        MkColMethod mkcol = new MkColMethod(mUri.toString() + WebdavUtils.encodePath(path));
-        try {
-            Log_OC.d(TAG, "Creating directory " + path);
-            status = executeMethod(mkcol);
-            Log_OC.d(TAG, "Status returned: " + status);
-            result = mkcol.succeeded();
-            
-            Log_OC.d(TAG, "MKCOL to " + path + " finished with HTTP status " + status + (!result?"(FAIL)":""));
-            exhaustResponse(mkcol.getResponseBodyAsStream());
-            
-        } catch (Exception e) {
-            logException(e, "creating directory " + path);
-            
-        } finally {
-            mkcol.releaseConnection();    // let the connection available for other methods
-        }
-        return result;
+    public void setBasicCredentials(String username, String password) {
+        List<String> authPrefs = new ArrayList<String>(1);
+        authPrefs.add(AuthPolicy.BASIC);
+        getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);        
+        
+        getParams().setAuthenticationPreemptive(true);
+        mCredentials = new UsernamePasswordCredentials(username, password);
+        getState().setCredentials(AuthScope.ANY, mCredentials);
     }
     
-    
     /**
      * Check if a file exists in the OC server
      * 
+     * TODO replace with ExistenceOperation
+     * 
      * @return              'true' if the file exists; 'false' it doesn't exist
      * @throws  Exception   When the existence could not be determined
      */
@@ -250,7 +114,7 @@ public class WebdavClient extends HttpClient {
             head.releaseConnection();    // let the connection available for other methods
         }
     }
-
+    
     /**
      * Requests the received method with the received timeout (milliseconds).
      * 
@@ -299,25 +163,6 @@ public class WebdavClient extends HttpClient {
         }
     }
 
-    /**
-     * Logs an exception triggered in a HTTP request. 
-     * 
-     * @param e         Caught exception.
-     * @param doing     Suffix to add at the end of the logged message.
-     */
-    private void logException(Exception e, String doing) {
-        if (e instanceof HttpException) {
-            Log_OC.e(TAG, "HTTP violation while " + doing, e);
-
-        } else if (e instanceof IOException) {
-            Log_OC.e(TAG, "Unrecovered transport exception while " + doing, e);
-
-        } else {
-            Log_OC.e(TAG, "Unexpected exception while " + doing, e);
-        }
-    }
-
-    
     /**
      * Sets the connection and wait-for-data timeouts to be applied by default to the methods performed by this client.
      */
@@ -338,4 +183,8 @@ public class WebdavClient extends HttpClient {
         return mUri;
     }
 
+    public final Credentials getCredentials() {
+        return mCredentials;
+    }
+
 }

+ 0 - 1
src/eu/alefzero/webdav/WebdavEntry.java

@@ -26,7 +26,6 @@ import org.apache.jackrabbit.webdav.property.DavPropertySet;
 import com.owncloud.android.Log_OC;
 
 import android.net.Uri;
-import android.util.Log;
 
 public class WebdavEntry {
     private String mName, mPath, mUri, mContentType;