Merge branch 'develop' into oauth_login
authorDavid A. Velasco <dvelasco@solidgear.es>
Thu, 25 Apr 2013 17:39:22 +0000 (19:39 +0200)
committerDavid A. Velasco <dvelasco@solidgear.es>
Thu, 25 Apr 2013 17:39:22 +0000 (19:39 +0200)
Conflicts:
AndroidManifest.xml
res/values/strings.xml
src/com/owncloud/android/Uploader.java
src/com/owncloud/android/authentication/AccountAuthenticator.java
src/com/owncloud/android/authenticator/AuthenticationRunnable.java
src/com/owncloud/android/authenticator/OnAuthenticationResultListener.java
src/com/owncloud/android/authenticator/OnConnectCheckListener.java
src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java
src/com/owncloud/android/files/services/FileDownloader.java
src/com/owncloud/android/files/services/FileOperation.java
src/com/owncloud/android/files/services/FileUploader.java
src/com/owncloud/android/network/OwnCloudClientUtils.java
src/com/owncloud/android/operations/RemoteOperationResult.java
src/com/owncloud/android/operations/UpdateOCVersionOperation.java
src/com/owncloud/android/syncadapter/FileSyncAdapter.java
src/com/owncloud/android/ui/activity/AccountSelectActivity.java
src/com/owncloud/android/ui/activity/AuthenticatorActivity.java
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/fragment/FileDetailFragment.java
src/eu/alefzero/webdav/WebdavClient.java

68 files changed:
1  2 
AndroidManifest.xml
res/layout-land/account_setup.xml
res/layout/account_setup.xml
res/values/strings.xml
res/values/styles.xml
src/com/owncloud/android/AccountUtils.java
src/com/owncloud/android/DisplayUtils.java
src/com/owncloud/android/Uploader.java
src/com/owncloud/android/authentication/AccountAuthenticator.java
src/com/owncloud/android/authentication/AccountAuthenticatorService.java
src/com/owncloud/android/authentication/AuthenticatorActivity.java
src/com/owncloud/android/authentication/OAuth2Constants.java
src/com/owncloud/android/datamodel/FileDataStorageManager.java
src/com/owncloud/android/db/DbHandler.java
src/com/owncloud/android/extensions/ExtensionsAvailableDialog.java
src/com/owncloud/android/extensions/ExtensionsListActivity.java
src/com/owncloud/android/files/BootupBroadcastReceiver.java
src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java
src/com/owncloud/android/files/OwnCloudFileObserver.java
src/com/owncloud/android/files/services/FileDownloader.java
src/com/owncloud/android/files/services/FileObserverService.java
src/com/owncloud/android/files/services/FileUploader.java
src/com/owncloud/android/location/LocationServiceLauncherReciever.java
src/com/owncloud/android/location/LocationUpdateService.java
src/com/owncloud/android/network/AdvancedSslSocketFactory.java
src/com/owncloud/android/network/AdvancedX509TrustManager.java
src/com/owncloud/android/network/BearerAuthScheme.java
src/com/owncloud/android/network/BearerCredentials.java
src/com/owncloud/android/network/OwnCloudClientUtils.java
src/com/owncloud/android/operations/ChunkedUploadFileOperation.java
src/com/owncloud/android/operations/CreateFolderOperation.java
src/com/owncloud/android/operations/DownloadFileOperation.java
src/com/owncloud/android/operations/ExistenceCheckOperation.java
src/com/owncloud/android/operations/OAuth2GetAccessToken.java
src/com/owncloud/android/operations/OwnCloudServerCheckOperation.java
src/com/owncloud/android/operations/RemoteOperation.java
src/com/owncloud/android/operations/RemoteOperationResult.java
src/com/owncloud/android/operations/RemoveFileOperation.java
src/com/owncloud/android/operations/RenameFileOperation.java
src/com/owncloud/android/operations/SynchronizeFileOperation.java
src/com/owncloud/android/operations/SynchronizeFolderOperation.java
src/com/owncloud/android/operations/UpdateOCVersionOperation.java
src/com/owncloud/android/providers/FileContentProvider.java
src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java
src/com/owncloud/android/syncadapter/ContactSyncAdapter.java
src/com/owncloud/android/syncadapter/FileSyncAdapter.java
src/com/owncloud/android/ui/activity/AccountSelectActivity.java
src/com/owncloud/android/ui/activity/ErrorsWhileCopyingHandlerActivity.java
src/com/owncloud/android/ui/activity/FailedUploadActivity.java
src/com/owncloud/android/ui/activity/FileDetailActivity.java
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/activity/InstantUploadActivity.java
src/com/owncloud/android/ui/activity/LandingActivity.java
src/com/owncloud/android/ui/activity/UploadFilesActivity.java
src/com/owncloud/android/ui/dialog/SslValidatorDialog.java
src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java
src/com/owncloud/android/ui/fragment/FileDetailFragment.java
src/com/owncloud/android/ui/fragment/LocalFileListFragment.java
src/com/owncloud/android/ui/fragment/OCFileListFragment.java
src/com/owncloud/android/ui/preview/FileDownloadFragment.java
src/com/owncloud/android/ui/preview/PreviewImageActivity.java
src/com/owncloud/android/ui/preview/PreviewImageFragment.java
src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java
src/com/owncloud/android/ui/preview/PreviewMediaFragment.java
src/com/owncloud/android/ui/preview/PreviewVideoActivity.java
src/com/owncloud/android/utils/FileStorageUtils.java
src/eu/alefzero/webdav/WebdavClient.java
src/eu/alefzero/webdav/WebdavEntry.java

- <?xml version="1.0" encoding="utf-8"?>\r
- <!-- \r
-   ownCloud Android client application\r
\r
-   Copyright (C) 2012  Bartek Przybylski\r
-   Copyright (C) 2012-2013 ownCloud Inc.\r
\r
-   This program is free software: you can redistribute it and/or modify\r
-   it under the terms of the GNU General Public License as published by\r
-   the Free Software Foundation, either version 2 of the License, or\r
-   (at your option) any later version.\r
\r
-   This program is distributed in the hope that it will be useful,\r
-   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-   GNU General Public License for more details.\r
\r
-   You should have received a copy of the GNU General Public License\r
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
-  -->\r
- <manifest package="com.owncloud.android"\r
-     android:versionCode="103022"\r
-     android:versionName="1.3.22" xmlns:android="http://schemas.android.com/apk/res/android">\r
\r
-     <uses-permission android:name="android.permission.GET_ACCOUNTS" />\r
-     <uses-permission android:name="android.permission.USE_CREDENTIALS" />\r
-     <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />\r
-     <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />\r
-     <uses-permission android:name="android.permission.INTERNET" />\r
-     <uses-permission android:name="android.permission.WRITE_SETTINGS" />\r
-     <uses-permission android:name="android.permission.READ_SYNC_STATS" />\r
-     <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />\r
-     <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />\r
-     <uses-permission android:name="android.permission.BROADCAST_STICKY" />\r
-     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />\r
-     <uses-permission android:name="android.permission.READ_PHONE_STATE" />\r
-     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>\r
\r
-     <uses-sdk\r
-         android:minSdkVersion="8"\r
-         android:targetSdkVersion="13" />\r
\r
-     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >\r
-     </uses-permission>\r
\r
-     <application\r
-         android:icon="@drawable/icon"\r
-         android:label="@string/app_name"\r
-         android:theme="@style/Theme.ownCloud"> \r
-         <activity\r
-             android:name=".ui.activity.FileDisplayActivity"\r
-             android:label="@string/app_name">\r
-             <intent-filter>\r
-                 <action android:name="android.intent.action.MAIN" />\r
\r
-                 <category android:name="android.intent.category.LAUNCHER" />\r
-             </intent-filter>\r
-         </activity>\r
-         <activity android:name=".ui.activity.UploadFilesActivity">\r
-         </activity>\r
-         <activity android:name=".Uploader" >\r
-             <intent-filter>\r
-                 <action android:name="android.intent.action.SEND" >\r
-                 </action>\r
\r
-                 <category android:name="android.intent.category.DEFAULT" >\r
-                 </category>\r
\r
-                 <data android:mimeType="*/*" >\r
-                 </data>\r
-             </intent-filter>\r
-             <intent-filter>\r
-                 <action android:name="android.intent.action.SEND_MULTIPLE" >\r
-                 </action>\r
\r
-                 <category android:name="android.intent.category.DEFAULT" >\r
-                 </category>\r
\r
-                 <data android:mimeType="*/*" >\r
-                 </data>\r
-             </intent-filter>\r
-         </activity>\r
-         <activity\r
-             android:name=".ui.activity.Preferences"\r
-             android:theme="@style/Theme.ownCloud" >\r
-         </activity>\r
-         <activity android:name=".ui.activity.PreferencesNewSessionewSession" >\r
-         </activity>\r
\r
-         <service\r
-             android:name=".authentication.AccountAuthenticatorService"\r
-             android:exported="true">\r
-             <intent-filter  android:priority="100">\r
-                 <action android:name="android.accounts.AccountAuthenticator" />\r
-             </intent-filter>\r
\r
-             <meta-data\r
-                 android:name="android.accounts.AccountAuthenticator"\r
-                 android:resource="@xml/authenticator" />\r
-         </service>\r
-         <service\r
-             android:name=".syncadapter.FileSyncService"\r
-             android:exported="true" >\r
-             <intent-filter>\r
-                 <action android:name="android.content.SyncAdapter" />\r
-             </intent-filter>\r
\r
-             <meta-data\r
-                 android:name="android.content.SyncAdapter"\r
-                 android:resource="@xml/syncadapter_files" />\r
-         </service>\r
\r
-         <provider\r
-             android:name=".providers.FileContentProvider"\r
-             android:authorities="org.owncloud"\r
-             android:enabled="true"\r
-             android:exported="false"\r
-             android:label="@string/sync_string_files"\r
-             android:syncable="true" >\r
-         </provider>\r
\r
-         <activity\r
-             android:name=".authentication.AuthenticatorActivity"\r
-             android:exported="true"\r
-             android:theme="@style/Theme.ownCloud.noActionBar" \r
-             android:launchMode="singleTask">\r
-             <intent-filter>\r
-                 <action android:name="android.intent.action.VIEW" />\r
-                 <category android:name="android.intent.category.DEFAULT" />\r
-                 <category android:name="android.intent.category.BROWSABLE" />\r
-                 <data android:scheme="@string/oauth2_redirect_scheme" />\r
-             </intent-filter>\r
-             <intent-filter>\r
-                 <action android:name="com.owncloud.android.workaround.accounts.CREATE" />\r
-                 <category android:name="android.intent.category.DEFAULT" />\r
-             </intent-filter>\r
-         </activity>\r
\r
-         <service android:name=".files.services.FileDownloader" >\r
-         </service>\r
\r
+ <?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/>.
+  -->
+ <manifest package="com.owncloud.android"
+     android:versionCode="104000"
+     android:versionName="1.4.0" xmlns:android="http://schemas.android.com/apk/res/android">
+     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+     <uses-permission android:name="android.permission.USE_CREDENTIALS" />
+     <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
+     <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
+     <uses-permission android:name="android.permission.INTERNET" />
+     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+     <uses-permission android:name="android.permission.READ_SYNC_STATS" />
+     <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
+     <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
+     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
+     <uses-permission android:name="android.permission.WAKE_LOCK"/>
+     
+     <uses-sdk
+         android:minSdkVersion="8"
+         android:targetSdkVersion="13" />
+     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
+     </uses-permission>
+     <application
+         android:icon="@drawable/icon"
+         android:label="@string/app_name"
+         android:theme="@style/Theme.ownCloud"> 
+         <activity
+             android:name=".ui.activity.FileDisplayActivity"
+             android:label="@string/app_name">
+             <intent-filter>
+                 <action android:name="android.intent.action.MAIN" />
+                 <category android:name="android.intent.category.LAUNCHER" />
+             </intent-filter>
+         </activity>
+         <activity android:name=".ui.activity.UploadFilesActivity">
+         </activity>
+               <activity android:name=".ui.activity.InstantUploadActivity">
+         </activity>
+         <activity android:name=".ui.activity.FailedUploadActivity" android:theme="@android:style/Theme.Dialog" android:excludeFromRecents="true"/>
+         <activity android:name=".Uploader" >
+             <intent-filter>
+                 <action android:name="android.intent.action.SEND" >
+                 </action>
+                 <category android:name="android.intent.category.DEFAULT" >
+                 </category>
+                 <data android:mimeType="*/*" >
+                 </data>
+             </intent-filter>
+             <intent-filter>
+                 <action android:name="android.intent.action.SEND_MULTIPLE" >
+                 </action>
+                 <category android:name="android.intent.category.DEFAULT" >
+                 </category>
+                 <data android:mimeType="*/*" >
+                 </data>
+             </intent-filter>
+         </activity>
+         <activity
+             android:name=".ui.activity.Preferences"
+             android:theme="@style/Theme.ownCloud" >
+         </activity>
+         <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"
+                                       android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
+               </activity>        
+         <service
 -            android:name=".authenticator.AccountAuthenticatorService"
++            android:name=".authentication.AccountAuthenticatorService"
+             android:exported="true">
+             <intent-filter  android:priority="100">
+                 <action android:name="android.accounts.AccountAuthenticator" />
+             </intent-filter>
+             <meta-data
+                 android:name="android.accounts.AccountAuthenticator"
+                 android:resource="@xml/authenticator" />
+         </service>
+         <service
+             android:name=".syncadapter.FileSyncService"
+             android:exported="true" >
+             <intent-filter>
+                 <action android:name="android.content.SyncAdapter" />
+             </intent-filter>
+             <meta-data
+                 android:name="android.content.SyncAdapter"
+                 android:resource="@xml/syncadapter_files" />
+         </service>
+         <provider
+             android:name=".providers.FileContentProvider"
+             android:authorities="org.owncloud"
+             android:enabled="true"
+             android:exported="false"
+             android:label="@string/sync_string_files"
+             android:syncable="true" >
+         </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" />
+             </intent-filter>
+         </activity>
+         <service android:name=".files.services.FileDownloader" />
+         <service android:name=".files.services.FileUploader" />
+         <service android:name=".media.MediaService" />
+         
          <activity android:name=".ui.activity.FileDetailActivity" />
-         <activity android:name=".ui.activity.PinCodeActivity" />\r
+         <activity android:name=".ui.activity.PinCodeActivity" />
          <activity android:name=".extensions.ExtensionsAvailableActivity"></activity>
-         <activity android:name=".extensions.ExtensionsListActivity"></activity>\r
-         <activity android:name=".ui.activity.AccountSelectActivity" android:uiOptions="none" android:label="@string/prefs_accounts"></activity>\r
+         <activity android:name=".extensions.ExtensionsListActivity"></activity>
+         <activity android:name=".ui.activity.AccountSelectActivity" android:uiOptions="none" android:label="@string/prefs_accounts"></activity>
          <activity android:name=".ui.activity.ConflictsResolveActivity"/>
-         <activity android:name=".ui.activity.GenericExplanationActivity"/>\r
-         <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>\r
+         <activity android:name=".ui.activity.GenericExplanationActivity"/>
+         <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>
+         
+         <activity android:name=".ui.activity.LogHistoryActivity"/>
          
-         <service android:name=".files.services.FileUploader" >\r
-         </service>
 -        <receiver android:name=".files.InstantUploadBroadcastReceiver">
 -            <intent-filter>
 -                <action android:name="com.android.camera.NEW_PICTURE" />
 -                <data android:mimeType="image/*" />
 +        <receiver android:name=".files.InstantUploadBroadcastReceiver">\r
 +            <intent-filter>\r
 +                <action android:name="com.android.camera.NEW_PICTURE" />\r
 +                <data android:mimeType="image/*" />\r
              </intent-filter>
              <intent-filter>
                  <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
Simple merge
Simple merge
      <string name="downloader_download_succeeded_content">%1$s was successfully downloaded</string>
      <string name="downloader_download_failed_ticker">Download failed</string>
      <string name="downloader_download_failed_content">Download of %1$s could not be completed</string>
+     <string name="downloader_not_downloaded_yet">Not downloaded yet</string>
      <string name="common_choose_account">Choose account</string>
      <string name="sync_string_contacts">Contacts</string>
-       <string name="sync_fail_ticker">Synchronization failed</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>
-       <string name="sync_foreign_files_forgotten_content">%1$d files out of the %2$s directory could not be copied into</string>
-       <string name="sync_foreign_files_forgotten_explanation">"As of version 1.3.16, files uploaded from this device are copied into the local %1$s folder to prevent data loss when a single file is synced with multiple accounts.\n\nDue to this change, all files uploaded in previous versions of this app were copied into the %2$s folder. However, an error prevented the completion of this operation during account synchronization. You may either leave the file(s) as is and remove the link to %3$s, or move the file(s) into the %1$s directory and retain the link to %4$s.\n\nListed below are the local file(s), and the the remote file(s) in %5$s they were linked to.</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>
+     <string name="sync_foreign_files_forgotten_content">%1$d files out of the %2$s directory could not be copied into</string>
+     <string name="sync_foreign_files_forgotten_explanation">"As of version 1.3.16, files uploaded from this device are copied into the local %1$s folder to prevent data loss when a single file is synced with multiple accounts.\n\nDue to this change, all files uploaded in previous versions of this app were copied into the %2$s folder. However, an error prevented the completion of this operation during account synchronization. You may either leave the file(s) as is and remove the link to %3$s, or move the file(s) into the %1$s directory and retain the link to %4$s.\n\nListed below are the local file(s), and the the remote file(s) in %5$s they were linked to.</string>
      <string name="foreign_files_move">"Move all"</string>
      <string name="foreign_files_success">"All files were moved"</string>
      <string name="foreign_files_fail">"Some files could not be moved"</string>
      <string name="auth_incorrect_path_message">Application couldn\'t find a server instance at the given path. Please check your path and try again.</string>
      <string name="auth_timeout_title">The server took too long to respond</string>
      <string name="auth_incorrect_address_title">Malformed URL</string>
-       <string name="auth_ssl_general_error_title">SSL initialization failed</string>
-       <string name="auth_ssl_unverified_server_title">Unverified SSL server\'s identity</string>
-       <string name="auth_bad_oc_version_title">Unrecognized server version</string>
-       <string name="auth_wrong_connection_title">Couldn\'t establish connection</string>
-       <string name="auth_secure_connection">Secure connection established</string>
+     <string name="auth_ssl_general_error_title">SSL initialization failed</string>
+     <string name="auth_ssl_unverified_server_title">Unverified SSL server\'s identity</string>
+     <string name="auth_bad_oc_version_title">Unrecognized server version</string>
+     <string name="auth_wrong_connection_title">Couldn\'t establish connection</string>
+     <string name="auth_secure_connection">Secure connection established</string>
      <string name="auth_login_details">Login details</string>
 -    <string name="auth_unauthorized">Invalid login / password</string>
 +    <string name="auth_unauthorized">Invalid credentials</string>
 +      <string name="auth_oauth_error">Unsuccessful authorization</string>
 +      <string name="auth_oauth_error_access_denied">Access denied by authorization server</string>
      <string name="auth_not_found">Wrong path given</string>
      <string name="auth_internal">Internal server error, code %1$d</string>
 +    <string name="auth_wtf_reenter_URL">Unexpected state; please, enter the server URL again</string>
 +    <string name="auth_expired_oauth_token_toast">Your authorization expired.\nPlease, authorize again</string>
 +    <string name="auth_expired_basic_auth_toast">Your saved credentials are invalid.\nPlease, enter the current credentials</string>
 +    
      <string name="crashlog_message">Application terminated unexpectedly. Would you like to submit a crash report?</string>
      <string name="crashlog_send_report">Send report</string>
      <string name="crashlog_dont_send_report">Don\'t send report</string>
      <string name="rename_dialog_title">Enter a new name</string>
      <string name="rename_local_fail_msg">"Local copy could not be renamed; try a different name"</string>
      <string name="rename_server_fail_msg">"Rename could not be completed"</string>
-         
-     <string name="sync_file_fail_msg">Remote file could not be checked</string> 
-     <string name="sync_file_nothing_to_do_msg">File contents already synchronized</string> 
-     
+     <string name="sync_file_fail_msg">Remote file could not be checked</string>
+     <string name="sync_file_nothing_to_do_msg">File contents already synchronized</string>
      <string name="create_dir_fail_msg">Directory could not be created</string>
-     
      <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>
Simple merge
@@@ -25,8 -24,8 +24,6 @@@ import java.util.HashMap
  import java.util.HashSet;\r
  import java.util.Set;\r
  \r
--import android.util.Log;\r
--\r
  /**\r
   * A helper class for some string operations.\r
   * \r
- /* ownCloud Android client application\r
-  *   Copyright (C) 2012  Bartek Przybylski\r
-  *   Copyright (C) 2012-2013 ownCloud Inc.\r
-  *\r
-  *   This program is free software: you can redistribute it and/or modify\r
-  *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 2 of the License, or\r
-  *   (at your option) any later version.\r
-  *\r
-  *   This program is distributed in the hope that it will be useful,\r
-  *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-  *   GNU General Public License for more details.\r
-  *\r
-  *   You should have received a copy of the GNU General Public License\r
-  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
-  *\r
-  */\r
- package com.owncloud.android;\r
\r
- import java.io.File;\r
- import java.util.ArrayList;\r
- import java.util.HashMap;\r
- import java.util.LinkedList;\r
- import java.util.List;\r
- import java.util.Stack;\r
- import java.util.Vector;\r
\r
- import com.owncloud.android.authentication.AccountAuthenticator;\r
- import com.owncloud.android.datamodel.DataStorageManager;\r
- import com.owncloud.android.datamodel.FileDataStorageManager;\r
- import com.owncloud.android.datamodel.OCFile;\r
- import com.owncloud.android.files.services.FileUploader;\r
\r
- import android.accounts.Account;\r
- import android.accounts.AccountManager;\r
- import android.app.AlertDialog;\r
- import android.app.AlertDialog.Builder;\r
- import android.app.Dialog;\r
- import android.app.ListActivity;\r
- import android.app.ProgressDialog;\r
- import android.content.Context;\r
- import android.content.DialogInterface;\r
- import android.content.DialogInterface.OnCancelListener;\r
- import android.content.DialogInterface.OnClickListener;\r
- import android.content.Intent;\r
- import android.database.Cursor;\r
- import android.net.Uri;\r
- import android.os.Bundle;\r
- import android.os.Parcelable;\r
- import android.provider.MediaStore.Images.Media;\r
- import android.util.Log;\r
- import android.view.View;\r
- import android.view.Window;\r
- import android.widget.AdapterView;\r
- import android.widget.AdapterView.OnItemClickListener;\r
- import android.widget.Button;\r
- import android.widget.EditText;\r
- import android.widget.SimpleAdapter;\r
- import android.widget.Toast;\r
\r
- import com.owncloud.android.R;\r
\r
- /**\r
-  * This can be used to upload things to an ownCloud instance.\r
-  * \r
-  * @author Bartek Przybylski\r
-  * \r
-  */\r
- public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener {\r
-     private static final String TAG = "ownCloudUploader";\r
\r
-     private Account mAccount;\r
-     private AccountManager mAccountManager;\r
-     private Stack<String> mParents;\r
-     private ArrayList<Parcelable> mStreamsToUpload;\r
-     private boolean mCreateDir;\r
-     private String mUploadPath;\r
-     private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE };\r
-     private DataStorageManager mStorageManager;\r
-     private OCFile mFile;\r
\r
-     private final static int DIALOG_NO_ACCOUNT = 0;\r
-     private final static int DIALOG_WAITING = 1;\r
-     private final static int DIALOG_NO_STREAM = 2;\r
-     private final static int DIALOG_MULTIPLE_ACCOUNT = 3;\r
-     //private final static int DIALOG_GET_DIRNAME = 4;\r
\r
-     private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;\r
\r
-     @Override\r
-     protected void onCreate(Bundle savedInstanceState) {\r
-         super.onCreate(savedInstanceState);\r
-         getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
-         mParents = new Stack<String>();\r
-         mParents.add("");\r
-         /*if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {\r
-             prepareStreamsToUpload();*/\r
-         if (prepareStreamsToUpload()) {\r
-             mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);\r
-             Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);\r
-             if (accounts.length == 0) {\r
-                 Log.i(TAG, "No ownCloud account is available");\r
-                 showDialog(DIALOG_NO_ACCOUNT);\r
-             } else if (accounts.length > 1) {\r
-                 Log.i(TAG, "More then one ownCloud is available");\r
-                 showDialog(DIALOG_MULTIPLE_ACCOUNT);\r
-             } else {\r
-                 mAccount = accounts[0];\r
-                 mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());\r
-                 populateDirectoryList();\r
-             }\r
-         } else {\r
-             showDialog(DIALOG_NO_STREAM);\r
-         }\r
-     }\r
-     \r
-     @Override\r
-     protected Dialog onCreateDialog(final int id) {\r
-         final AlertDialog.Builder builder = new Builder(this);\r
-         switch (id) {\r
-         case DIALOG_WAITING:\r
-             ProgressDialog pDialog = new ProgressDialog(this);\r
-             pDialog.setIndeterminate(false);\r
-             pDialog.setCancelable(false);\r
-             pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading));\r
-             return pDialog;\r
-         case DIALOG_NO_ACCOUNT:\r
-             builder.setIcon(android.R.drawable.ic_dialog_alert);\r
-             builder.setTitle(R.string.uploader_wrn_no_account_title);\r
-             builder.setMessage(String.format(getString(R.string.uploader_wrn_no_account_text), getString(R.string.app_name)));\r
-             builder.setCancelable(false);\r
-             builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {\r
-                 @Override\r
-                 public void onClick(DialogInterface dialog, int which) {\r
-                     if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {\r
-                         // using string value since in API7 this\r
-                         // constatn is not defined\r
-                         // in API7 < this constatant is defined in\r
-                         // Settings.ADD_ACCOUNT_SETTINGS\r
-                         // and Settings.EXTRA_AUTHORITIES\r
-                         Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);\r
-                         intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTHORITY });\r
-                         startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);\r
-                     } else {\r
-                         // since in API7 there is no direct call for\r
-                         // account setup, so we need to\r
-                         // show our own AccountSetupAcricity, get\r
-                         // desired results and setup\r
-                         // everything for ourself\r
-                         Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);\r
-                         startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);\r
-                     }\r
-                 }\r
-             });\r
-             builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {\r
-                 @Override\r
-                 public void onClick(DialogInterface dialog, int which) {\r
-                     finish();\r
-                 }\r
-             });\r
-             return builder.create();\r
-         /*case DIALOG_GET_DIRNAME:\r
-             final EditText dirName = new EditText(getBaseContext());\r
-             builder.setView(dirName);\r
-             builder.setTitle(R.string.uploader_info_dirname);\r
-             String pathToUpload;\r
-             if (mParents.empty()) {\r
-                 pathToUpload = "/";\r
-             } else {\r
-                 mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), null,\r
-                         null, null, null);\r
-                 mCursor.moveToFirst();\r
-                 pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH))\r
-                         + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20");   // TODO don't make this ; use WebdavUtils.encode in the right moment\r
-             }\r
-             a a = new a(pathToUpload, dirName);\r
-             builder.setPositiveButton(R.string.common_ok, a);\r
-             builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {\r
-                 public void onClick(DialogInterface dialog, int which) {\r
-                     dialog.cancel();\r
-                 }\r
-             });\r
-             return builder.create();*/\r
-         case DIALOG_MULTIPLE_ACCOUNT:\r
-             CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length];\r
-             for (int i = 0; i < ac.length; ++i) {\r
-                 ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name;\r
-             }\r
-             builder.setTitle(R.string.common_choose_account);\r
-             builder.setItems(ac, new OnClickListener() {\r
-                 @Override\r
-                 public void onClick(DialogInterface dialog, int which) {\r
-                     mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which];\r
-                     mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());\r
-                     populateDirectoryList();\r
-                 }\r
-             });\r
-             builder.setCancelable(true);\r
-             builder.setOnCancelListener(new OnCancelListener() {\r
-                 @Override\r
-                 public void onCancel(DialogInterface dialog) {\r
-                     dialog.cancel();\r
-                     finish();\r
-                 }\r
-             });\r
-             return builder.create();\r
-         case DIALOG_NO_STREAM:\r
-             builder.setIcon(android.R.drawable.ic_dialog_alert);\r
-             builder.setTitle(R.string.uploader_wrn_no_content_title);\r
-             builder.setMessage(R.string.uploader_wrn_no_content_text);\r
-             builder.setCancelable(false);\r
-             builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {\r
-                 @Override\r
-                 public void onClick(DialogInterface dialog, int which) {\r
-                     finish();\r
-                 }\r
-             });\r
-             return builder.create();\r
-         default:\r
-             throw new IllegalArgumentException("Unknown dialog id: " + id);\r
-         }\r
-     }\r
\r
-     class a implements OnClickListener {\r
-         String mPath;\r
-         EditText mDirname;\r
\r
-         public a(String path, EditText dirname) {\r
-             mPath = path; \r
-             mDirname = dirname;\r
-         }\r
\r
-         @Override\r
-         public void onClick(DialogInterface dialog, int which) {\r
-             Uploader.this.mUploadPath = mPath + mDirname.getText().toString();\r
-             Uploader.this.mCreateDir = true;\r
-             uploadFiles();\r
-         }\r
-     }\r
\r
-     @Override\r
-     public void onBackPressed() {\r
\r
-         if (mParents.size() <= 1) {\r
-             super.onBackPressed();\r
-             return;\r
-         } else {\r
-             mParents.pop();\r
-             populateDirectoryList();\r
-         }\r
-     }\r
\r
-     @Override\r
-     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\r
-         // click on folder in the list\r
-         Log.d(TAG, "on item click");\r
-         Vector<OCFile> tmpfiles = mStorageManager.getDirectoryContent(mFile);\r
-         if (tmpfiles.size() <= 0) return;\r
-         // filter on dirtype\r
-         Vector<OCFile> files = new Vector<OCFile>();\r
-         for (OCFile f : tmpfiles)\r
-             if (f.isDirectory())\r
-                 files.add(f);\r
-         if (files.size() < position) {\r
-             throw new IndexOutOfBoundsException("Incorrect item selected");\r
-         }\r
-         mParents.push(files.get(position).getFileName());\r
-         populateDirectoryList();\r
-     }\r
\r
-     @Override\r
-     public void onClick(View v) {\r
-         // click on button\r
-         switch (v.getId()) {\r
-         case R.id.uploader_choose_folder:\r
-             mUploadPath = "";   // first element in mParents is root dir, represented by ""; init mUploadPath with "/" results in a "//" prefix\r
-             for (String p : mParents)\r
-                 mUploadPath += p + OCFile.PATH_SEPARATOR;\r
-             Log.d(TAG, "Uploading file to dir " + mUploadPath);\r
\r
-             uploadFiles();\r
\r
-             break;\r
-         /*case android.R.id.button1: // dynamic action for create aditional dir\r
-             showDialog(DIALOG_GET_DIRNAME);\r
-             break;*/\r
-         default:\r
-             throw new IllegalArgumentException("Wrong element clicked");\r
-         }\r
-     }\r
\r
-     @Override\r
-     protected void onActivityResult(int requestCode, int resultCode, Intent data) {\r
-         super.onActivityResult(requestCode, resultCode, data);\r
-         Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);\r
-         if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {\r
-             dismissDialog(DIALOG_NO_ACCOUNT);\r
-             if (resultCode == RESULT_CANCELED) {\r
-                 finish();\r
-             }\r
-             Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE);\r
-             if (accounts.length == 0) {\r
-                 showDialog(DIALOG_NO_ACCOUNT);\r
-             } else {\r
-                 // there is no need for checking for is there more then one\r
-                 // account at this point\r
-                 // since account setup can set only one account at time\r
-                 mAccount = accounts[0];\r
-                 populateDirectoryList();\r
-             }\r
-         }\r
-     }\r
\r
-     private void populateDirectoryList() {\r
-         setContentView(R.layout.uploader_layout);\r
\r
-         String full_path = "";\r
-         for (String a : mParents)\r
-             full_path += a + "/";\r
-         \r
-         Log.d(TAG, "Populating view with content of : " + full_path);\r
-         \r
-         mFile = mStorageManager.getFileByPath(full_path);\r
-         if (mFile != null) {\r
-             Vector<OCFile> files = mStorageManager.getDirectoryContent(mFile);\r
-             List<HashMap<String, Object>> data = new LinkedList<HashMap<String,Object>>();\r
-             for (OCFile f : files) {\r
-                 HashMap<String, Object> h = new HashMap<String, Object>();\r
-                 if (f.isDirectory()) {\r
-                     h.put("dirname", f.getFileName());\r
-                     data.add(h);\r
-                 }\r
-             }\r
-             SimpleAdapter sa = new SimpleAdapter(this,\r
-                                                 data,\r
-                                                 R.layout.uploader_list_item_layout,\r
-                                                 new String[] {"dirname"},\r
-                                                 new int[] {R.id.textView1});\r
-             setListAdapter(sa);\r
-             Button btn = (Button) findViewById(R.id.uploader_choose_folder);\r
-             btn.setOnClickListener(this);\r
-             getListView().setOnItemClickListener(this);\r
-         }\r
-     }\r
\r
-     private boolean prepareStreamsToUpload() {\r
-         if (getIntent().getAction().equals(Intent.ACTION_SEND)) {\r
-             mStreamsToUpload = new ArrayList<Parcelable>();\r
-             mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));\r
-         } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {\r
-             mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);\r
-         }\r
-         return (mStreamsToUpload != null && mStreamsToUpload.get(0) != null);\r
-     }\r
\r
-     public void uploadFiles() {\r
-         try {\r
-             /* TODO - mCreateDir can never be true at this moment; we will replace wdc.createDirectory by CreateFolderOperation when that is fixed \r
-             WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext());\r
-             // create last directory in path if necessary\r
-             if (mCreateDir) {\r
-                 wdc.createDirectory(mUploadPath);\r
-             }\r
-             */\r
\r
-             String[] local = new String[mStreamsToUpload.size()], remote = new String[mStreamsToUpload.size()];\r
\r
-             for (int i = 0; i < mStreamsToUpload.size(); ++i) {\r
-                 Uri uri = (Uri) mStreamsToUpload.get(i);\r
-                 if (uri.getScheme().equals("content")) {\r
-                     Cursor c = getContentResolver().query((Uri) mStreamsToUpload.get(i),\r
-                                                       CONTENT_PROJECTION,\r
-                                                       null,\r
-                                                       null,\r
-                                                       null);\r
\r
-                     if (!c.moveToFirst())\r
-                         continue;\r
\r
-                     final String display_name = c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),\r
-                                 data = c.getString(c.getColumnIndex(Media.DATA));\r
-                     local[i] = data;\r
-                     remote[i] = mUploadPath + display_name;\r
-                 } else if (uri.getScheme().equals("file")) {\r
-                     final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme() + "://", ""));\r
-                     local[i] = file.getAbsolutePath();\r
-                     remote[i] = mUploadPath + file.getName();\r
-                 }\r
\r
-             }\r
-             Intent intent = new Intent(getApplicationContext(), FileUploader.class);\r
-             intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);\r
-             intent.putExtra(FileUploader.KEY_LOCAL_FILE, local);\r
-             intent.putExtra(FileUploader.KEY_REMOTE_FILE, remote);\r
-             intent.putExtra(FileUploader.KEY_ACCOUNT, mAccount);\r
-             startService(intent);\r
-             finish();\r
-             \r
-         } catch (SecurityException e) {\r
-             String message = String.format(getString(R.string.uploader_error_forbidden_content), getString(R.string.app_name));\r
-             Toast.makeText(this, message, Toast.LENGTH_LONG).show();            \r
-         }\r
-     }\r
\r
- }\r
+ /* 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;
+ import java.io.File;
+ import java.util.ArrayList;
+ import java.util.HashMap;
+ import java.util.LinkedList;
+ 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;
+ import android.app.AlertDialog;
+ import android.app.AlertDialog.Builder;
+ import android.app.Dialog;
+ import android.app.ListActivity;
+ import android.app.ProgressDialog;
+ import android.content.Context;
+ import android.content.DialogInterface;
+ import android.content.DialogInterface.OnCancelListener;
+ import android.content.DialogInterface.OnClickListener;
+ import android.content.Intent;
+ import android.database.Cursor;
+ 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;
+ import android.widget.AdapterView.OnItemClickListener;
+ import android.widget.Button;
+ import android.widget.EditText;
+ 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.
+  * 
+  * @author Bartek Przybylski
+  * 
+  */
+ public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener {
+     private static final String TAG = "ownCloudUploader";
+     private Account mAccount;
+     private AccountManager mAccountManager;
+     private Stack<String> mParents;
+     private ArrayList<Parcelable> mStreamsToUpload;
+     private boolean mCreateDir;
+     private String mUploadPath;
+     private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE };
+     private DataStorageManager mStorageManager;
+     private OCFile mFile;
+     private final static int DIALOG_NO_ACCOUNT = 0;
+     private final static int DIALOG_WAITING = 1;
+     private final static int DIALOG_NO_STREAM = 2;
+     private final static int DIALOG_MULTIPLE_ACCOUNT = 3;
+     //private final static int DIALOG_GET_DIRNAME = 4;
+     private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;
+     @Override
+     protected void onCreate(Bundle savedInstanceState) {
+         super.onCreate(savedInstanceState);
+         getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+         mParents = new Stack<String>();
+         mParents.add("");
+         /*if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {
+             prepareStreamsToUpload();*/
+         if (prepareStreamsToUpload()) {
+             mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);
+             Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);
+             if (accounts.length == 0) {
+                 Log_OC.i(TAG, "No ownCloud account is available");
+                 showDialog(DIALOG_NO_ACCOUNT);
+             } else if (accounts.length > 1) {
+                 Log_OC.i(TAG, "More then one ownCloud is available");
+                 showDialog(DIALOG_MULTIPLE_ACCOUNT);
+             } else {
+                 mAccount = accounts[0];
+                 mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
+                 populateDirectoryList();
+             }
+         } else {
+             showDialog(DIALOG_NO_STREAM);
+         }
+     }
+     
+     @Override
+     protected Dialog onCreateDialog(final int id) {
+         final AlertDialog.Builder builder = new Builder(this);
+         switch (id) {
+         case DIALOG_WAITING:
+             ProgressDialog pDialog = new ProgressDialog(this);
+             pDialog.setIndeterminate(false);
+             pDialog.setCancelable(false);
+             pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading));
+             return pDialog;
+         case DIALOG_NO_ACCOUNT:
+             builder.setIcon(android.R.drawable.ic_dialog_alert);
+             builder.setTitle(R.string.uploader_wrn_no_account_title);
+             builder.setMessage(String.format(getString(R.string.uploader_wrn_no_account_text), getString(R.string.app_name)));
+             builder.setCancelable(false);
+             builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {
+                 @Override
+                 public void onClick(DialogInterface dialog, int which) {
+                     if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {
+                         // using string value since in API7 this
+                         // constatn is not defined
+                         // 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
+                         // account setup, so we need to
+                         // show our own AccountSetupAcricity, get
+                         // desired results and setup
+                         // everything for ourself
+                         Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);
+                         startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
+                     }
+                 }
+             });
+             builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {
+                 @Override
+                 public void onClick(DialogInterface dialog, int which) {
+                     finish();
+                 }
+             });
+             return builder.create();
+         /*case DIALOG_GET_DIRNAME:
+             final EditText dirName = new EditText(getBaseContext());
+             builder.setView(dirName);
+             builder.setTitle(R.string.uploader_info_dirname);
+             String pathToUpload;
+             if (mParents.empty()) {
+                 pathToUpload = "/";
+             } else {
+                 mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), null,
+                         null, null, null);
+                 mCursor.moveToFirst();
+                 pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH))
+                         + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20");   // TODO don't make this ; use WebdavUtils.encode in the right moment
+             }
+             a a = new a(pathToUpload, dirName);
+             builder.setPositiveButton(R.string.common_ok, a);
+             builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {
+                 public void onClick(DialogInterface dialog, int which) {
+                     dialog.cancel();
+                 }
+             });
+             return builder.create();*/
+         case DIALOG_MULTIPLE_ACCOUNT:
+             CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length];
+             for (int i = 0; i < ac.length; ++i) {
+                 ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name;
+             }
+             builder.setTitle(R.string.common_choose_account);
+             builder.setItems(ac, new OnClickListener() {
+                 @Override
+                 public void onClick(DialogInterface dialog, int which) {
+                     mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which];
+                     mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
+                     populateDirectoryList();
+                 }
+             });
+             builder.setCancelable(true);
+             builder.setOnCancelListener(new OnCancelListener() {
+                 @Override
+                 public void onCancel(DialogInterface dialog) {
+                     dialog.cancel();
+                     finish();
+                 }
+             });
+             return builder.create();
+         case DIALOG_NO_STREAM:
+             builder.setIcon(android.R.drawable.ic_dialog_alert);
+             builder.setTitle(R.string.uploader_wrn_no_content_title);
+             builder.setMessage(R.string.uploader_wrn_no_content_text);
+             builder.setCancelable(false);
+             builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {
+                 @Override
+                 public void onClick(DialogInterface dialog, int which) {
+                     finish();
+                 }
+             });
+             return builder.create();
+         default:
+             throw new IllegalArgumentException("Unknown dialog id: " + id);
+         }
+     }
+     class a implements OnClickListener {
+         String mPath;
+         EditText mDirname;
+         public a(String path, EditText dirname) {
+             mPath = path; 
+             mDirname = dirname;
+         }
+         @Override
+         public void onClick(DialogInterface dialog, int which) {
+             Uploader.this.mUploadPath = mPath + mDirname.getText().toString();
+             Uploader.this.mCreateDir = true;
+             uploadFiles();
+         }
+     }
+     @Override
+     public void onBackPressed() {
+         if (mParents.size() <= 1) {
+             super.onBackPressed();
+             return;
+         } else {
+             mParents.pop();
+             populateDirectoryList();
+         }
+     }
+     @Override
+     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+         // click on folder in the list
+         Log_OC.d(TAG, "on item click");
+         Vector<OCFile> tmpfiles = mStorageManager.getDirectoryContent(mFile);
+         if (tmpfiles.size() <= 0) return;
+         // filter on dirtype
+         Vector<OCFile> files = new Vector<OCFile>();
+         for (OCFile f : tmpfiles)
+             if (f.isDirectory())
+                 files.add(f);
+         if (files.size() < position) {
+             throw new IndexOutOfBoundsException("Incorrect item selected");
+         }
+         mParents.push(files.get(position).getFileName());
+         populateDirectoryList();
+     }
+     @Override
+     public void onClick(View v) {
+         // click on button
+         switch (v.getId()) {
+         case R.id.uploader_choose_folder:
+             mUploadPath = "";   // first element in mParents is root dir, represented by ""; init mUploadPath with "/" results in a "//" prefix
+             for (String p : mParents)
+                 mUploadPath += p + OCFile.PATH_SEPARATOR;
+             Log_OC.d(TAG, "Uploading file to dir " + mUploadPath);
+             uploadFiles();
+             break;
+         /*case android.R.id.button1: // dynamic action for create aditional dir
+             showDialog(DIALOG_GET_DIRNAME);
+             break;*/
+         default:
+             throw new IllegalArgumentException("Wrong element clicked");
+         }
+     }
+     @Override
+     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+         super.onActivityResult(requestCode, resultCode, data);
+         Log_OC.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);
+         if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {
+             dismissDialog(DIALOG_NO_ACCOUNT);
+             if (resultCode == RESULT_CANCELED) {
+                 finish();
+             }
+             Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE);
+             if (accounts.length == 0) {
+                 showDialog(DIALOG_NO_ACCOUNT);
+             } else {
+                 // there is no need for checking for is there more then one
+                 // account at this point
+                 // since account setup can set only one account at time
+                 mAccount = accounts[0];
+                 populateDirectoryList();
+             }
+         }
+     }
+     private void populateDirectoryList() {
+         setContentView(R.layout.uploader_layout);
+         String full_path = "";
+         for (String a : mParents)
+             full_path += a + "/";
+         
+         Log_OC.d(TAG, "Populating view with content of : " + full_path);
+         
+         mFile = mStorageManager.getFileByPath(full_path);
+         if (mFile != null) {
+             Vector<OCFile> files = mStorageManager.getDirectoryContent(mFile);
+             List<HashMap<String, Object>> data = new LinkedList<HashMap<String,Object>>();
+             for (OCFile f : files) {
+                 HashMap<String, Object> h = new HashMap<String, Object>();
+                 if (f.isDirectory()) {
+                     h.put("dirname", f.getFileName());
+                     data.add(h);
+                 }
+             }
+             SimpleAdapter sa = new SimpleAdapter(this,
+                                                 data,
+                                                 R.layout.uploader_list_item_layout,
+                                                 new String[] {"dirname"},
+                                                 new int[] {R.id.textView1});
+             setListAdapter(sa);
+             Button btn = (Button) findViewById(R.id.uploader_choose_folder);
+             btn.setOnClickListener(this);
+             getListView().setOnItemClickListener(this);
+         }
+     }
+     private boolean prepareStreamsToUpload() {
+         if (getIntent().getAction().equals(Intent.ACTION_SEND)) {
+             mStreamsToUpload = new ArrayList<Parcelable>();
+             mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));
+         } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {
+             mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+         }
+         return (mStreamsToUpload != null && mStreamsToUpload.get(0) != null);
+     }
+     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()];
+             for (int i = 0; i < mStreamsToUpload.size(); ++i) {
+                 Uri uri = (Uri) mStreamsToUpload.get(i);
+                 if (uri.getScheme().equals("content")) {
+                     Cursor c = getContentResolver().query((Uri) mStreamsToUpload.get(i),
+                                                       CONTENT_PROJECTION,
+                                                       null,
+                                                       null,
+                                                       null);
+                     if (!c.moveToFirst())
+                         continue;
+                     final String display_name = c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),
+                                 data = c.getString(c.getColumnIndex(Media.DATA));
+                     local[i] = data;
+                     remote[i] = mUploadPath + display_name;
+                 } else if (uri.getScheme().equals("file")) {
+                     final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme() + "://", ""));
+                     local[i] = file.getAbsolutePath();
+                     remote[i] = mUploadPath + file.getName();
+                 }
+             }
+             Intent intent = new Intent(getApplicationContext(), FileUploader.class);
+             intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
+             intent.putExtra(FileUploader.KEY_LOCAL_FILE, local);
+             intent.putExtra(FileUploader.KEY_REMOTE_FILE, remote);
+             intent.putExtra(FileUploader.KEY_ACCOUNT, mAccount);
+             startService(intent);
+             finish();
+             
+         } catch (SecurityException e) {
+             String message = String.format(getString(R.string.uploader_error_forbidden_content), getString(R.string.app_name));
+             Toast.makeText(this, message, Toast.LENGTH_LONG).show();            
+         }
+     }
+ }
index d6acbbb,0000000..aa12993
mode 100644,000000..100644
--- /dev/null
@@@ -1,318 -1,0 +1,315 @@@
- /* ownCloud Android client application\r
-  *   Copyright (C) 2012  Bartek Przybylski\r
-  *   Copyright (C) 2012-2013 ownCloud Inc.\r
-  *\r
-  *   This program is free software: you can redistribute it and/or modify\r
-  *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 2 of the License, or\r
-  *   (at your option) any later version.\r
-  *\r
-  *   This program is distributed in the hope that it will be useful,\r
-  *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-  *   GNU General Public License for more details.\r
-  *\r
-  *   You should have received a copy of the GNU General Public License\r
-  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
-  *\r
-  */\r
\r
- package com.owncloud.android.authentication;\r
\r
\r
- import android.accounts.*;\r
- import android.content.Context;\r
- import android.content.Intent;\r
- import android.os.Bundle;\r
- import android.util.Log;\r
\r
\r
- /**\r
-  *  Authenticator for ownCloud accounts.\r
-  * \r
-  *  Controller class accessed from the system AccountManager, providing integration of ownCloud accounts with the Android system.\r
-  * \r
-  *  TODO - better separation in operations for OAuth-capable and regular ownCloud accounts.\r
-  *  TODO - review completeness \r
-  * \r
-  * @author David A. Velasco\r
-  */\r
- public class AccountAuthenticator extends AbstractAccountAuthenticator {\r
-     /**\r
-      * Is used by android system to assign accounts to authenticators. Should be\r
-      * used by application and all extensions.\r
-      */\r
-     public static final String ACCOUNT_TYPE = "owncloud";\r
-     public static final String AUTHORITY = "org.owncloud";\r
-     public static final String AUTH_TOKEN_TYPE = "org.owncloud";\r
-     public static final String AUTH_TOKEN_TYPE_PASSWORD = "owncloud.password";\r
-     public static final String AUTH_TOKEN_TYPE_ACCESS_TOKEN = "owncloud.oauth2.access_token";\r
-     public static final String AUTH_TOKEN_TYPE_REFRESH_TOKEN = "owncloud.oauth2.refresh_token";\r
\r
-     public static final String KEY_AUTH_TOKEN_TYPE = "authTokenType";\r
-     public static final String KEY_REQUIRED_FEATURES = "requiredFeatures";\r
-     public static final String KEY_LOGIN_OPTIONS = "loginOptions";\r
-     public static final String KEY_ACCOUNT = "account";\r
-     /**\r
-      * Value under this key should handle path to webdav php script. Will be\r
-      * removed and usage should be replaced by combining\r
-      * {@link com.owncloud.android.authentication.AuthenticatorActivity.KEY_OC_BASE_URL} and\r
-      * {@link com.owncloud.android.utils.OwnCloudVersion}\r
-      * \r
-      * @deprecated\r
-      */\r
-     public static final String KEY_OC_URL = "oc_url";\r
-     /**\r
-      * Version should be 3 numbers separated by dot so it can be parsed by\r
-      * {@link com.owncloud.android.utils.OwnCloudVersion}\r
-      */\r
-     public static final String KEY_OC_VERSION = "oc_version";\r
-     /**\r
-      * Base url should point to owncloud installation without trailing / ie:\r
-      * http://server/path or https://owncloud.server\r
-      */\r
-     public static final String KEY_OC_BASE_URL = "oc_base_url";\r
-     /**\r
-      * Flag signaling if the ownCloud server can be accessed with OAuth2 access tokens.\r
-      */\r
-     public static final String KEY_SUPPORTS_OAUTH2 = "oc_supports_oauth2";\r
-     \r
-     private static final String TAG = AccountAuthenticator.class.getSimpleName();\r
-     \r
-     private Context mContext;\r
\r
-     public AccountAuthenticator(Context context) {\r
-         super(context);\r
-         mContext = context;\r
-     }\r
\r
-     /**\r
-      * {@inheritDoc}\r
-      */\r
-     @Override\r
-     public Bundle addAccount(AccountAuthenticatorResponse response,\r
-             String accountType, String authTokenType,\r
-             String[] requiredFeatures, Bundle options)\r
-             throws NetworkErrorException {\r
-         Log.i(TAG, "Adding account with type " + accountType\r
-                 + " and auth token " + authTokenType);\r
-         try {\r
-             validateAccountType(accountType);\r
-         } catch (AuthenticatorException e) {\r
-             Log.e(TAG, "Failed to validate account type " + accountType + ": "\r
-                     + e.getMessage());\r
-             e.printStackTrace();\r
-             return e.getFailureBundle();\r
-         }\r
-         final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
-         intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);\r
-         intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
-         intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures);\r
-         intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
-         intent.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_CREATE);\r
\r
-         setIntentFlags(intent);\r
-         \r
-         final Bundle bundle = new Bundle();\r
-         bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
-         return bundle;\r
-     }\r
\r
++/* 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 android.accounts.*;
++import android.content.Context;
++import android.content.Intent;
++import android.os.Bundle;
++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.authentication.AuthenticatorActivity.KEY_OC_BASE_URL} and
++     * {@link com.owncloud.android.utils.OwnCloudVersion}
++     * 
++     * @deprecated
++     */
++    public static final String KEY_OC_URL = "oc_url";
++    /**
++     * Version should be 3 numbers separated by dot so it can be parsed by
++     * {@link com.owncloud.android.utils.OwnCloudVersion}
++     */
++    public static final String KEY_OC_VERSION = "oc_version";
++    /**
++     * Base url should point to owncloud installation without trailing / ie:
++     * http://server/path or https://owncloud.server
++     */
++    public static final String KEY_OC_BASE_URL = "oc_base_url";
++    /**
++     * 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) {
++        super(context);
++        mContext = context;
++    }
++
++    /**
++     * {@inheritDoc}
++     */
++    @Override
++    public Bundle addAccount(AccountAuthenticatorResponse response,
++            String accountType, String authTokenType,
++            String[] requiredFeatures, Bundle options)
++            throws NetworkErrorException {
++        Log_OC.i(TAG, "Adding account with type " + accountType
++                + " and auth token " + authTokenType);
++        try {
++            validateAccountType(accountType);
++        } catch (AuthenticatorException e) {
++            Log_OC.e(TAG, "Failed to validate account type " + accountType + ": "
++                    + e.getMessage());
++            e.printStackTrace();
++            return e.getFailureBundle();
++        }
++        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
++        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;
++    }
++
 +    /**\r
 +     * {@inheritDoc}\r
 +     */\r
 +    @Override\r
 +    public Bundle confirmCredentials(AccountAuthenticatorResponse response,\r
 +            Account account, Bundle options) throws NetworkErrorException {\r
 +        try {\r
 +            validateAccountType(account.type);\r
 +        } catch (AuthenticatorException e) {\r
-             Log.e(TAG, "Failed to validate account type " + account.type + ": "\r
++            Log_OC.e(TAG, "Failed to validate account type " + account.type + ": "\r
 +                    + e.getMessage());\r
 +            e.printStackTrace();\r
 +            return e.getFailureBundle();\r
 +        }\r
 +        Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
 +        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
 +                response);\r
 +        intent.putExtra(KEY_ACCOUNT, account);\r
 +        intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
 +\r
 +        setIntentFlags(intent);\r
 +\r
 +        Bundle resultBundle = new Bundle();\r
 +        resultBundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
 +        return resultBundle;\r
 +    }\r
 +\r
 +    @Override\r
 +    public Bundle editProperties(AccountAuthenticatorResponse response,\r
 +            String accountType) {\r
 +        return null;\r
 +    }\r
 +\r
-     /**\r
-      * {@inheritDoc}\r
-      */\r
-     @Override\r
-     public Bundle getAuthToken(AccountAuthenticatorResponse response,\r
-             Account account, String authTokenType, Bundle options)\r
-             throws NetworkErrorException {\r
-         /// validate parameters\r
-         try {\r
-             validateAccountType(account.type);\r
-             validateAuthTokenType(authTokenType);\r
-         } catch (AuthenticatorException e) {\r
-             Log.e(TAG, "Failed to validate account type " + account.type + ": "\r
-                     + e.getMessage());\r
-             e.printStackTrace();\r
-             return e.getFailureBundle();\r
-         }\r
-         \r
-         /// check if required token is stored\r
-         final AccountManager am = AccountManager.get(mContext);\r
-         String accessToken;\r
-         if (authTokenType.equals(AUTH_TOKEN_TYPE_PASSWORD)) {\r
-             accessToken = am.getPassword(account);\r
-         } else {\r
-             accessToken = am.peekAuthToken(account, authTokenType);\r
-         }\r
-         if (accessToken != null) {\r
-             final Bundle result = new Bundle();\r
-             result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);\r
-             result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);\r
-             result.putString(AccountManager.KEY_AUTHTOKEN, accessToken);\r
-             return result;\r
-         }\r
-         \r
-         /// if not stored, return Intent to access the AuthenticatorActivity and UPDATE the token for the account\r
-         final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
-         intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);\r
-         intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
-         intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
-         intent.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, account);\r
-         intent.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);\r
-         \r
\r
-         final Bundle bundle = new Bundle();\r
-         bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
-         return bundle;\r
-     }\r
\r
-     @Override\r
-     public String getAuthTokenLabel(String authTokenType) {\r
-         return null;\r
-     }\r
\r
-     @Override\r
-     public Bundle hasFeatures(AccountAuthenticatorResponse response,\r
-             Account account, String[] features) throws NetworkErrorException {\r
-         final Bundle result = new Bundle();\r
-         result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);\r
-         return result;\r
-     }\r
\r
-     @Override\r
-     public Bundle updateCredentials(AccountAuthenticatorResponse response,\r
-             Account account, String authTokenType, Bundle options)\r
-             throws NetworkErrorException {\r
-         final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
-         intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
-                 response);\r
-         intent.putExtra(KEY_ACCOUNT, account);\r
-         intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
-         intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
-         setIntentFlags(intent);\r
\r
-         final Bundle bundle = new Bundle();\r
-         bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
-         return bundle;\r
-     }\r
\r
-     @Override\r
-     public Bundle getAccountRemovalAllowed(\r
-             AccountAuthenticatorResponse response, Account account)\r
-             throws NetworkErrorException {\r
-         return super.getAccountRemovalAllowed(response, account);\r
-     }\r
\r
-     private void setIntentFlags(Intent intent) {\r
-         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\r
-         //intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);\r
-         //intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); // incompatible with the authorization code grant in OAuth\r
-         intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);\r
-         intent.addFlags(Intent.FLAG_FROM_BACKGROUND);\r
-     }\r
\r
-     private void validateAccountType(String type)\r
-             throws UnsupportedAccountTypeException {\r
-         if (!type.equals(ACCOUNT_TYPE)) {\r
-             throw new UnsupportedAccountTypeException();\r
-         }\r
-     }\r
\r
++    /**
++     * {@inheritDoc}
++     */
++    @Override
++    public Bundle getAuthToken(AccountAuthenticatorResponse response,
++            Account account, String authTokenType, Bundle options)
++            throws NetworkErrorException {
++        /// validate parameters
++        try {
++            validateAccountType(account.type);
++            validateAuthTokenType(authTokenType);
++        } catch (AuthenticatorException e) {
++            Log_OC.e(TAG, "Failed to validate account type " + account.type + ": "
++                    + e.getMessage());
++            e.printStackTrace();
++            return e.getFailureBundle();
++        }
++        
++        /// check if required token is stored
++        final AccountManager am = AccountManager.get(mContext);
++        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, 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(KEY_AUTH_TOKEN_TYPE, authTokenType);
++        intent.putExtra(KEY_LOGIN_OPTIONS, options);
++        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);
++        return bundle;
++    }
++
++    @Override
++    public String getAuthTokenLabel(String authTokenType) {
++        return null;
++    }
++
++    @Override
++    public Bundle hasFeatures(AccountAuthenticatorResponse response,
++            Account account, String[] features) throws NetworkErrorException {
++        final Bundle result = new Bundle();
++        result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
++        return result;
++    }
++
++    @Override
++    public Bundle updateCredentials(AccountAuthenticatorResponse response,
++            Account account, String authTokenType, Bundle options)
++            throws NetworkErrorException {
++        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
++        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
++                response);
++        intent.putExtra(KEY_ACCOUNT, account);
++        intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
++        intent.putExtra(KEY_LOGIN_OPTIONS, options);
++        setIntentFlags(intent);
++
++        final Bundle bundle = new Bundle();
++        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
++        return bundle;
++    }
++
++    @Override
++    public Bundle getAccountRemovalAllowed(
++            AccountAuthenticatorResponse response, Account account)
++            throws NetworkErrorException {
++        return super.getAccountRemovalAllowed(response, account);
++    }
++
++    private void setIntentFlags(Intent intent) {
++        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
++        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
++        intent.addFlags(Intent.FLAG_FROM_BACKGROUND);
++    }
++
++    private void validateAccountType(String type)
++            throws UnsupportedAccountTypeException {
++        if (!type.equals(ACCOUNT_TYPE)) {
++            throw new UnsupportedAccountTypeException();
++        }
++    }
++
 +    private void validateAuthTokenType(String authTokenType)\r
 +            throws UnsupportedAuthTokenTypeException {\r
 +        if (!authTokenType.equals(AUTH_TOKEN_TYPE) &&\r
 +            !authTokenType.equals(AUTH_TOKEN_TYPE_PASSWORD) &&\r
 +            !authTokenType.equals(AUTH_TOKEN_TYPE_ACCESS_TOKEN) &&\r
 +            !authTokenType.equals(AUTH_TOKEN_TYPE_REFRESH_TOKEN) ) {\r
 +            throw new UnsupportedAuthTokenTypeException();\r
 +        }\r
 +    }\r
 +\r
 +    public static class AuthenticatorException extends Exception {\r
 +        private static final long serialVersionUID = 1L;\r
 +        private Bundle mFailureBundle;\r
 +\r
 +        public AuthenticatorException(int code, String errorMsg) {\r
 +            mFailureBundle = new Bundle();\r
 +            mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code);\r
 +            mFailureBundle\r
 +                    .putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);\r
 +        }\r
 +\r
 +        public Bundle getFailureBundle() {\r
 +            return mFailureBundle;\r
 +        }\r
 +    }\r
 +\r
 +    public static class UnsupportedAccountTypeException extends\r
 +            AuthenticatorException {\r
 +        private static final long serialVersionUID = 1L;\r
 +\r
 +        public UnsupportedAccountTypeException() {\r
 +            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
 +                    "Unsupported account type");\r
 +        }\r
 +    }\r
 +\r
 +    public static class UnsupportedAuthTokenTypeException extends\r
 +            AuthenticatorException {\r
 +        private static final long serialVersionUID = 1L;\r
 +\r
 +        public UnsupportedAuthTokenTypeException() {\r
 +            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
 +                    "Unsupported auth token type");\r
 +        }\r
 +    }\r
 +\r
 +    public static class UnsupportedFeaturesException extends\r
 +            AuthenticatorException {\r
 +        public static final long serialVersionUID = 1L;\r
 +\r
 +        public UnsupportedFeaturesException() {\r
 +            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
 +                    "Unsupported features");\r
 +        }\r
 +    }\r
 +\r
 +    public static class AccessDeniedException extends AuthenticatorException {\r
 +        public AccessDeniedException(int code, String errorMsg) {\r
 +            super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied");\r
 +        }\r
 +\r
 +        private static final long serialVersionUID = 1L;\r
 +\r
 +    }\r
 +}\r
index 971d6f0,0000000..c6a77d5
mode 100644,000000..100644
--- /dev/null
@@@ -1,42 -1,0 +1,41 @@@
-  *   it under the terms of the GNU General Public License as published by
-  *   the Free Software Foundation, either version 2 of the License, or
-  *   (at your option) any later version.
 +/* ownCloud Android client application
 + *   Copyright (C) 2011  Bartek Przybylski
 + *   Copyright (C) 2012-2013 ownCloud Inc.
 + *
 + *   This program is free software: you can redistribute it and/or modify
++ *   it under the terms of the GNU General Public License 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 android.app.Service;
 +import android.content.Intent;
 +import android.os.IBinder;
 +
 +public class AccountAuthenticatorService extends Service {
 +
 +    private AccountAuthenticator mAuthenticator;
 +    static final public String ACCOUNT_TYPE = "owncloud";
 +
 +    @Override
 +    public void onCreate() {
 +        super.onCreate();
 +        mAuthenticator = new AccountAuthenticator(this);
 +    }
 +
 +    @Override
 +    public IBinder onBind(Intent intent) {
 +        return mAuthenticator.getIBinder();
 +    }
 +
 +}
index cc1b648,0000000..ef5c21b
mode 100644,000000..100644
--- /dev/null
@@@ -1,1086 -1,0 +1,1085 @@@
-  *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 2 of the License, or\r
-  *   (at your option) any later version.\r
 +/* ownCloud Android client application\r
 + *   Copyright (C) 2012  Bartek Przybylski\r
 + *   Copyright (C) 2012-2013 ownCloud Inc.\r
 + *\r
 + *   This program is free software: you can redistribute it and/or modify\r
- import android.util.Log;\r
++ *   it under the terms of the GNU General Public License version 2,\r
++ *   as published by the Free Software Foundation.\r
 + *\r
 + *   This program is distributed in the hope that it will be useful,\r
 + *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
 + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
 + *   GNU General Public License for more details.\r
 + *\r
 + *   You should have received a copy of the GNU General Public License\r
 + *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
 + *\r
 + */\r
 +\r
 +package com.owncloud.android.authentication;\r
 +\r
 +import com.owncloud.android.AccountUtils;\r
++import com.owncloud.android.Log_OC;\r
 +import com.owncloud.android.ui.dialog.SslValidatorDialog;\r
 +import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;\r
 +import com.owncloud.android.utils.OwnCloudVersion;\r
 +import com.owncloud.android.network.OwnCloudClientUtils;\r
 +import com.owncloud.android.operations.OwnCloudServerCheckOperation;\r
 +import com.owncloud.android.operations.ExistenceCheckOperation;\r
 +import com.owncloud.android.operations.OAuth2GetAccessToken;\r
 +import com.owncloud.android.operations.OnRemoteOperationListener;\r
 +import com.owncloud.android.operations.RemoteOperation;\r
 +import com.owncloud.android.operations.RemoteOperationResult;\r
 +import com.owncloud.android.operations.RemoteOperationResult.ResultCode;\r
 +\r
 +import android.accounts.Account;\r
 +import android.accounts.AccountAuthenticatorActivity;\r
 +import android.accounts.AccountManager;\r
 +import android.app.AlertDialog;\r
 +import android.app.Dialog;\r
 +import android.app.ProgressDialog;\r
 +import android.content.ContentResolver;\r
 +import android.content.DialogInterface;\r
 +import android.content.Intent;\r
 +import android.content.SharedPreferences;\r
 +import android.net.Uri;\r
 +import android.os.Bundle;\r
 +import android.os.Handler;\r
 +import android.preference.PreferenceManager;\r
 +import android.text.InputType;\r
-         Log.d(TAG, "onNewIntent()");\r
 +import android.view.View;\r
 +import android.view.View.OnFocusChangeListener;\r
 +import android.view.Window;\r
 +import android.widget.CheckBox;\r
 +import android.widget.EditText;\r
 +import android.widget.Button;\r
 +import android.widget.ImageView;\r
 +import android.widget.TextView;\r
 +import android.widget.Toast;\r
 +\r
 +import com.owncloud.android.R;\r
 +\r
 +import eu.alefzero.webdav.WebdavClient;\r
 +\r
 +/**\r
 + * This Activity is used to add an ownCloud account to the App\r
 + * \r
 + * @author Bartek Przybylski\r
 + * @author David A. Velasco\r
 + */\r
 +public class AuthenticatorActivity extends AccountAuthenticatorActivity\r
 +        implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeListener {\r
 +\r
 +    private static final String TAG = AuthenticatorActivity.class.getSimpleName();\r
 +\r
 +    public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
 +    public static final String EXTRA_USER_NAME = "USER_NAME";\r
 +    public static final String EXTRA_HOST_NAME = "HOST_NAME";\r
 +    public static final String EXTRA_ACTION = "ACTION";\r
 +    \r
 +    private static final String KEY_HOST_URL_TEXT = "HOST_URL_TEXT";\r
 +    private static final String KEY_OC_VERSION = "OC_VERSION";\r
 +    private static final String KEY_ACCOUNT = "ACCOUNT";\r
 +    private static final String KEY_STATUS_TEXT = "STATUS_TEXT";\r
 +    private static final String KEY_STATUS_ICON = "STATUS_ICON";\r
 +    private static final String KEY_STATUS_CORRECT = "STATUS_CORRECT";\r
 +    private static final String KEY_IS_SSL_CONN = "IS_SSL_CONN";\r
 +    private static final String KEY_OAUTH2_STATUS_TEXT = "OAUTH2_STATUS_TEXT";\r
 +    private static final String KEY_OAUTH2_STATUS_ICON = "OAUTH2_STATUS_ICON";\r
 +    \r
 +    private static final String OAUTH_MODE_ON = "on";\r
 +    private static final String OAUTH_MODE_OFF = "off";\r
 +    private static final String OAUTH_MODE_OPTIONAL = "optional";\r
 +\r
 +    private static final int DIALOG_LOGIN_PROGRESS = 0;\r
 +    private static final int DIALOG_SSL_VALIDATOR = 1;\r
 +    private static final int DIALOG_CERT_NOT_SAVED = 2;\r
 +    private static final int DIALOG_OAUTH2_LOGIN_PROGRESS = 3;\r
 +\r
 +    public static final byte ACTION_CREATE = 0;\r
 +    public static final byte ACTION_UPDATE_TOKEN = 1;\r
 +\r
 +    \r
 +    private String mHostBaseUrl;\r
 +    private OwnCloudVersion mDiscoveredVersion;\r
 +    \r
 +    private int mStatusText, mStatusIcon;\r
 +    private boolean mStatusCorrect, mIsSslConn;\r
 +    private int mOAuth2StatusText, mOAuth2StatusIcon;    \r
 +    \r
 +    private final Handler mHandler = new Handler();\r
 +    private Thread mOperationThread;\r
 +    private OwnCloudServerCheckOperation mOcServerChkOperation;\r
 +    private ExistenceCheckOperation mAuthCheckOperation;\r
 +    private RemoteOperationResult mLastSslUntrustedServerResult;\r
 +\r
 +    private Uri mNewCapturedUriFromOAuth2Redirection;\r
 +    \r
 +    private AccountManager mAccountMgr;\r
 +    private boolean mJustCreated;\r
 +    private byte mAction;\r
 +    private Account mAccount;\r
 +    \r
 +    private ImageView mRefreshButton;\r
 +    private ImageView mViewPasswordButton;\r
 +    private EditText mHostUrlInput;\r
 +    private EditText mUsernameInput;\r
 +    private EditText mPasswordInput;\r
 +    private CheckBox mOAuth2Check;\r
 +    private String mOAuthAccessToken;\r
 +    private View mOkButton;\r
 +    private TextView mAuthStatusLayout;\r
 +    \r
 +    private TextView mOAuthAuthEndpointText;\r
 +    private TextView mOAuthTokenEndpointText;\r
 +    \r
 +    \r
 +    /**\r
 +     * {@inheritDoc}\r
 +     * \r
 +     * IMPORTANT ENTRY POINT 1: activity is shown to the user\r
 +     */\r
 +    @Override\r
 +    protected void onCreate(Bundle savedInstanceState) {\r
 +        super.onCreate(savedInstanceState);\r
 +        getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
 +        \r
 +        /// set view and get references to view elements\r
 +        setContentView(R.layout.account_setup);\r
 +        mRefreshButton = (ImageView) findViewById(R.id.refreshButton);\r
 +        mViewPasswordButton = (ImageView) findViewById(R.id.viewPasswordButton);\r
 +        mHostUrlInput = (EditText) findViewById(R.id.hostUrlInput);\r
 +        mUsernameInput = (EditText) findViewById(R.id.account_username);\r
 +        mPasswordInput = (EditText) findViewById(R.id.account_password);\r
 +        mOAuthAuthEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_1);\r
 +        mOAuthTokenEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_2);\r
 +        mOAuth2Check = (CheckBox) findViewById(R.id.oauth_onOff_check);\r
 +        mOkButton = findViewById(R.id.buttonOK);\r
 +        mAuthStatusLayout = (TextView) findViewById(R.id.auth_status_text); \r
 +        \r
 +        /// complete label for 'register account' button\r
 +        Button b = (Button) findViewById(R.id.account_register);\r
 +        if (b != null) {\r
 +            b.setText(String.format(getString(R.string.auth_register), getString(R.string.app_name)));\r
 +        }\r
 +\r
 +        /// bind view elements to listeners\r
 +        mHostUrlInput.setOnFocusChangeListener(this);\r
 +        mPasswordInput.setOnFocusChangeListener(this);\r
 +        \r
 +        /// initialization\r
 +        mAccountMgr = AccountManager.get(this);\r
 +        mNewCapturedUriFromOAuth2Redirection = null;\r
 +        mAction = getIntent().getByteExtra(EXTRA_ACTION, ACTION_CREATE); \r
 +        mAccount = null;\r
 +\r
 +        if (savedInstanceState == null) {\r
 +            /// connection state and info\r
 +            mStatusText = mStatusIcon = 0;\r
 +            mStatusCorrect = false;\r
 +            mIsSslConn = false;\r
 +            \r
 +            /// retrieve extras from intent\r
 +            String tokenType = getIntent().getExtras().getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE);\r
 +            boolean oAuthRequired = AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN.equals(tokenType) || OAUTH_MODE_ON.equals(getString(R.string.oauth2_mode));\r
 +            \r
 +            mAccount = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT);\r
 +            if (mAccount != null) {\r
 +                String ocVersion = mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION);\r
 +                if (ocVersion != null) {\r
 +                    mDiscoveredVersion = new OwnCloudVersion(ocVersion);\r
 +                }\r
 +                mHostBaseUrl = mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL);\r
 +                mHostUrlInput.setText(mHostBaseUrl);\r
 +                String userName = mAccount.name.substring(0, mAccount.name.lastIndexOf('@'));\r
 +                mUsernameInput.setText(userName);\r
 +                oAuthRequired = (mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null);\r
 +            }\r
 +            mOAuth2Check.setChecked(oAuthRequired);\r
 +            changeViewByOAuth2Check(oAuthRequired);\r
 +            \r
 +\r
 +        } else {\r
 +            loadSavedInstanceState(savedInstanceState);\r
 +        }\r
 +        \r
 +        if (!OAUTH_MODE_OPTIONAL.equals(getString(R.string.oauth2_mode))) {\r
 +            mOAuth2Check.setVisibility(View.GONE);\r
 +        }\r
 +        \r
 +        if (mAction == ACTION_UPDATE_TOKEN) {\r
 +            /// lock things that should not change\r
 +            mHostUrlInput.setEnabled(false);\r
 +            mUsernameInput.setEnabled(false);\r
 +            mOAuth2Check.setVisibility(View.GONE);\r
 +            checkOcServer(); \r
 +        }\r
 +        \r
 +        mPasswordInput.setText("");     // clean password to avoid social hacking (disadvantage: password in removed if the device is turned aside)\r
 +        mJustCreated = true;\r
 +    }\r
 +\r
 +\r
 +    /**\r
 +     * Saves relevant state before {@link #onPause()}\r
 +     * \r
 +     * Do NOT save {@link #mNewCapturedUriFromOAuth2Redirection}; it keeps a temporal flag, intended to defer the \r
 +     * processing of the redirection caught in {@link #onNewIntent(Intent)} until {@link #onResume()} \r
 +     * \r
 +     * See {@link #loadSavedInstanceState(Bundle)}\r
 +     */\r
 +    @Override\r
 +    protected void onSaveInstanceState(Bundle outState) {\r
 +        super.onSaveInstanceState(outState);\r
 +        \r
 +        /// connection state and info\r
 +        outState.putInt(KEY_STATUS_TEXT, mStatusText);\r
 +        outState.putInt(KEY_STATUS_ICON, mStatusIcon);\r
 +        outState.putBoolean(KEY_STATUS_CORRECT, mStatusCorrect);\r
 +        outState.putBoolean(KEY_IS_SSL_CONN, mIsSslConn);\r
 +\r
 +        /// server data\r
 +        if (mDiscoveredVersion != null) \r
 +            outState.putString(KEY_OC_VERSION, mDiscoveredVersion.toString());\r
 +        outState.putString(KEY_HOST_URL_TEXT, mHostBaseUrl);\r
 +        \r
 +        /// account data, if updating\r
 +        if (mAccount != null)\r
 +            outState.putParcelable(KEY_ACCOUNT, mAccount);\r
 +        \r
 +        // Saving the state of oAuth2 components.\r
 +        outState.putInt(KEY_OAUTH2_STATUS_ICON, mOAuth2StatusIcon);\r
 +        outState.putInt(KEY_OAUTH2_STATUS_TEXT, mOAuth2StatusText);\r
 +        \r
 +    }\r
 +\r
 +\r
 +    /**\r
 +     * Loads saved state\r
 +     * \r
 +     * See {@link #onSaveInstanceState(Bundle)}.\r
 +     * \r
 +     * @param savedInstanceState    Saved state, as received in {@link #onCreate(Bundle)}.\r
 +     */\r
 +    private void loadSavedInstanceState(Bundle savedInstanceState) {\r
 +        /// connection state and info\r
 +        mStatusCorrect = savedInstanceState.getBoolean(KEY_STATUS_CORRECT);\r
 +        mIsSslConn = savedInstanceState.getBoolean(KEY_IS_SSL_CONN);\r
 +        mStatusText = savedInstanceState.getInt(KEY_STATUS_TEXT);\r
 +        mStatusIcon = savedInstanceState.getInt(KEY_STATUS_ICON);\r
 +        updateConnStatus();\r
 +        \r
 +        /// UI settings depending upon connection\r
 +        mOkButton.setEnabled(mStatusCorrect);   // TODO really necessary?\r
 +        if (!mStatusCorrect)\r
 +            mRefreshButton.setVisibility(View.VISIBLE); // seems that setting visibility is necessary\r
 +        else\r
 +            mRefreshButton.setVisibility(View.INVISIBLE);\r
 +        \r
 +        /// server data\r
 +        String ocVersion = savedInstanceState.getString(KEY_OC_VERSION);\r
 +        if (ocVersion != null)\r
 +            mDiscoveredVersion = new OwnCloudVersion(ocVersion);\r
 +        mHostBaseUrl = savedInstanceState.getString(KEY_HOST_URL_TEXT);\r
 +        \r
 +        // account data, if updating\r
 +        mAccount = savedInstanceState.getParcelable(KEY_ACCOUNT);\r
 +        \r
 +        // state of oAuth2 components\r
 +        mOAuth2StatusIcon = savedInstanceState.getInt(KEY_OAUTH2_STATUS_ICON);\r
 +        mOAuth2StatusText = savedInstanceState.getInt(KEY_OAUTH2_STATUS_TEXT);\r
 +        // END of getting the state of oAuth2 components.\r
 +    }\r
 +\r
 +    \r
 +    /**\r
 +     * The redirection triggered by the OAuth authentication server as response to the GET AUTHORIZATION request\r
 +     * is caught here.\r
 +     * \r
 +     * To make this possible, this activity needs to be qualified with android:launchMode = "singleTask" in the\r
 +     * AndroidManifest.xml file.\r
 +     */\r
 +    @Override\r
 +    protected void onNewIntent (Intent intent) {\r
-             Log.wtf(TAG,  "The user was allowed to click 'connect' to an unchecked server!!");\r
++        Log_OC.d(TAG, "onNewIntent()");\r
 +        Uri data = intent.getData();\r
 +        if (data != null && data.toString().startsWith(getString(R.string.oauth2_redirect_uri))) {\r
 +            mNewCapturedUriFromOAuth2Redirection = data;\r
 +        }\r
 +    }\r
 +\r
 +    \r
 +    /**\r
 +     * The redirection triggered by the OAuth authentication server as response to the GET AUTHORIZATION, and \r
 +     * deferred in {@link #onNewIntent(Intent)}, is processed here.\r
 +     */\r
 +    @Override\r
 +    protected void onResume() {\r
 +        super.onResume();\r
 +        // the state of mOAuth2Check is automatically recovered between configuration changes, but not before onCreate() finishes; so keep the next lines here\r
 +        changeViewByOAuth2Check(mOAuth2Check.isChecked());  \r
 +        if (mAction == ACTION_UPDATE_TOKEN && mJustCreated) {\r
 +            if (mOAuth2Check.isChecked())\r
 +                Toast.makeText(this, R.string.auth_expired_oauth_token_toast, Toast.LENGTH_LONG).show();\r
 +            else\r
 +                Toast.makeText(this, R.string.auth_expired_basic_auth_toast, Toast.LENGTH_LONG).show();\r
 +        }\r
 +        \r
 +        if (mNewCapturedUriFromOAuth2Redirection != null) {\r
 +            getOAuth2AccessTokenFromCapturedRedirection();            \r
 +        }\r
 +        \r
 +        mJustCreated = false;\r
 +    }\r
 +    \r
 +    \r
 +    /**\r
 +     * Parses the redirection with the response to the GET AUTHORIZATION request to the \r
 +     * oAuth server and requests for the access token (GET ACCESS TOKEN)\r
 +     */\r
 +    private void getOAuth2AccessTokenFromCapturedRedirection() {\r
 +        /// Parse data from OAuth redirection\r
 +        String queryParameters = mNewCapturedUriFromOAuth2Redirection.getQuery();\r
 +        mNewCapturedUriFromOAuth2Redirection = null;\r
 +        \r
 +        /// Showing the dialog with instructions for the user.\r
 +        showDialog(DIALOG_OAUTH2_LOGIN_PROGRESS);\r
 +\r
 +        /// GET ACCESS TOKEN to the oAuth server \r
 +        RemoteOperation operation = new OAuth2GetAccessToken(   getString(R.string.oauth2_client_id), \r
 +                                                                getString(R.string.oauth2_redirect_uri), // TODO check - necessary here?      \r
 +                                                                getString(R.string.oauth2_grant_type),\r
 +                                                                queryParameters);\r
 +        //WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(getString(R.string.oauth2_url_endpoint_access)), getApplicationContext());\r
 +        WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mOAuthTokenEndpointText.getText().toString().trim()), getApplicationContext());\r
 +        operation.execute(client, this, mHandler);\r
 +    }\r
 +    \r
 +\r
 +    \r
 +    /**\r
 +     * Handles the change of focus on the text inputs for the server URL and the password\r
 +     */\r
 +    public void onFocusChange(View view, boolean hasFocus) {\r
 +        if (view.getId() == R.id.hostUrlInput) {\r
 +            onUrlInputFocusChanged((TextView) view, hasFocus);\r
 +            \r
 +        } else if (view.getId() == R.id.account_password) {\r
 +            onPasswordFocusChanged((TextView) view, hasFocus);\r
 +        }\r
 +    }\r
 +    \r
 +\r
 +    /**\r
 +     * Handles changes in focus on the text input for the server URL.\r
 +     * \r
 +     * IMPORTANT ENTRY POINT 2: When (!hasFocus), user wrote the server URL and changed to \r
 +     * other field. The operation to check the existence of the server in the entered URL is\r
 +     * started. \r
 +     * \r
 +     * When hasFocus:    user 'comes back' to write again the server URL.\r
 +     * \r
 +     * @param hostInput     TextView with the URL input field receiving the change of focus.\r
 +     * @param hasFocus      'True' if focus is received, 'false' if is lost\r
 +     */\r
 +    private void onUrlInputFocusChanged(TextView hostInput, boolean hasFocus) {\r
 +        if (!hasFocus) {\r
 +            checkOcServer();\r
 +            \r
 +        } else {\r
 +            // avoids that the 'connect' button can be clicked if the test was previously passed\r
 +            mOkButton.setEnabled(false); \r
 +        }\r
 +    }\r
 +\r
 +\r
 +    private void checkOcServer() {\r
 +        String uri = mHostUrlInput.getText().toString().trim();\r
 +        if (uri.length() != 0) {\r
 +            mStatusText = R.string.auth_testing_connection;\r
 +            mStatusIcon = R.drawable.progress_small;\r
 +            updateConnStatus();\r
 +            /** TODO cancel previous connection check if the user tries to ammend a wrong URL  \r
 +            if(mConnChkOperation != null) {\r
 +                mConnChkOperation.cancel();\r
 +            } */\r
 +            mOcServerChkOperation = new  OwnCloudServerCheckOperation(uri, this);\r
 +            WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this);\r
 +            mHostBaseUrl = "";\r
 +            mDiscoveredVersion = null;\r
 +            mOperationThread = mOcServerChkOperation.execute(client, this, mHandler);\r
 +        } else {\r
 +            mRefreshButton.setVisibility(View.INVISIBLE);\r
 +            mStatusText = 0;\r
 +            mStatusIcon = 0;\r
 +            updateConnStatus();\r
 +        }\r
 +    }\r
 +\r
 +\r
 +    /**\r
 +     * Handles changes in focus on the text input for the password (basic authorization).\r
 +     * \r
 +     * When (hasFocus), the button to toggle password visibility is shown.\r
 +     * \r
 +     * When (!hasFocus), the button is made invisible and the password is hidden.\r
 +     * \r
 +     * @param passwordInput    TextView with the password input field receiving the change of focus.\r
 +     * @param hasFocus          'True' if focus is received, 'false' if is lost\r
 +     */\r
 +    private void onPasswordFocusChanged(TextView passwordInput, boolean hasFocus) {\r
 +        if (hasFocus) {\r
 +            mViewPasswordButton.setVisibility(View.VISIBLE);\r
 +        } else {\r
 +            int input_type = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD;\r
 +            passwordInput.setInputType(input_type);\r
 +            mViewPasswordButton.setVisibility(View.INVISIBLE);\r
 +        }\r
 +    }\r
 +\r
 +\r
 +    \r
 +    /**\r
 +     * Cancels the authenticator activity\r
 +     * \r
 +     * IMPORTANT ENTRY POINT 3: Never underestimate the importance of cancellation\r
 +     * \r
 +     * This method is bound in the layout/acceoun_setup.xml resource file.\r
 +     * \r
 +     * @param view      Cancel button\r
 +     */\r
 +    public void onCancelClick(View view) {\r
 +        setResult(RESULT_CANCELED);     // TODO review how is this related to AccountAuthenticator (debugging)\r
 +        finish();\r
 +    }\r
 +    \r
 +    \r
 +    \r
 +    /**\r
 +     * Checks the credentials of the user in the root of the ownCloud server\r
 +     * before creating a new local account.\r
 +     * \r
 +     * For basic authorization, a check of existence of the root folder is\r
 +     * performed.\r
 +     * \r
 +     * For OAuth, starts the flow to get an access token; the credentials test \r
 +     * is postponed until it is available.\r
 +     * \r
 +     * IMPORTANT ENTRY POINT 4\r
 +     * \r
 +     * @param view      OK button\r
 +     */\r
 +    public void onOkClick(View view) {\r
 +        // this check should be unnecessary\r
 +        if (mDiscoveredVersion == null || !mDiscoveredVersion.isVersionValid()  || mHostBaseUrl == null || mHostBaseUrl.length() == 0) {\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_wtf_reenter_URL;\r
 +            updateConnStatus();\r
 +            mOkButton.setEnabled(false);\r
-         Log.d(TAG, "Starting browser to view " + uri.toString());\r
++            Log_OC.wtf(TAG,  "The user was allowed to click 'connect' to an unchecked server!!");\r
 +            return;\r
 +        }\r
 +        \r
 +        if (mOAuth2Check.isChecked()) {\r
 +            startOauthorization();\r
 +            \r
 +        } else {\r
 +            checkBasicAuthorization();\r
 +        }\r
 +    }\r
 +    \r
 +    \r
 +    /**\r
 +     * Tests the credentials entered by the user performing a check of existence on \r
 +     * the root folder of the ownCloud server.\r
 +     */\r
 +    private void checkBasicAuthorization() {\r
 +        /// get the path to the root folder through WebDAV from the version server\r
 +        String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, false);\r
 +        \r
 +        /// get basic credentials entered by user\r
 +        String username = mUsernameInput.getText().toString();\r
 +        String password = mPasswordInput.getText().toString();\r
 +        \r
 +        /// be gentle with the user\r
 +        showDialog(DIALOG_LOGIN_PROGRESS);\r
 +        \r
 +        /// test credentials accessing the root folder\r
 +        mAuthCheckOperation = new  ExistenceCheckOperation("", this, false);\r
 +        WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this);\r
 +        client.setBasicCredentials(username, password);\r
 +        mOperationThread = mAuthCheckOperation.execute(client, this, mHandler);\r
 +    }\r
 +\r
 +\r
 +    /**\r
 +     * Starts the OAuth 'grant type' flow to get an access token, with \r
 +     * a GET AUTHORIZATION request to the BUILT-IN authorization server. \r
 +     */\r
 +    private void startOauthorization() {\r
 +        // be gentle with the user\r
 +        mStatusIcon = R.drawable.progress_small;\r
 +        mStatusText = R.string.oauth_login_connection;\r
 +        updateAuthStatus();\r
 +        \r
 +        // GET AUTHORIZATION request\r
 +        //Uri uri = Uri.parse(getString(R.string.oauth2_url_endpoint_auth));\r
 +        Uri uri = Uri.parse(mOAuthAuthEndpointText.getText().toString().trim());\r
 +        Uri.Builder uriBuilder = uri.buildUpon();\r
 +        uriBuilder.appendQueryParameter(OAuth2Constants.KEY_RESPONSE_TYPE, getString(R.string.oauth2_response_type));\r
 +        uriBuilder.appendQueryParameter(OAuth2Constants.KEY_REDIRECT_URI, getString(R.string.oauth2_redirect_uri));   \r
 +        uriBuilder.appendQueryParameter(OAuth2Constants.KEY_CLIENT_ID, getString(R.string.oauth2_client_id));\r
 +        uriBuilder.appendQueryParameter(OAuth2Constants.KEY_SCOPE, getString(R.string.oauth2_scope));\r
 +        //uriBuilder.appendQueryParameter(OAuth2Constants.KEY_STATE, whateverwewant);\r
 +        uri = uriBuilder.build();\r
-             Log.d(TAG, "Got ACCESS TOKEN: " + mOAuthAccessToken);\r
++        Log_OC.d(TAG, "Starting browser to view " + uri.toString());\r
 +        Intent i = new Intent(Intent.ACTION_VIEW, uri);\r
 +        startActivity(i);\r
 +    }\r
 +\r
 +    \r
 +    /**\r
 +     * Callback method invoked when a RemoteOperation executed by this Activity finishes.\r
 +     * \r
 +     * Dispatches the operation flow to the right method.\r
 +     */\r
 +    @Override\r
 +    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {\r
 +\r
 +        if (operation instanceof OwnCloudServerCheckOperation) {\r
 +            onOcServerCheckFinish((OwnCloudServerCheckOperation) operation, result);\r
 +            \r
 +        } else if (operation instanceof OAuth2GetAccessToken) {\r
 +            onGetOAuthAccessTokenFinish((OAuth2GetAccessToken)operation, result);\r
 +                \r
 +        } else if (operation instanceof ExistenceCheckOperation)  {\r
 +            onAuthorizationCheckFinish((ExistenceCheckOperation)operation, result);\r
 +                \r
 +        }\r
 +    }\r
 +    \r
 +\r
 +    /**\r
 +     * Processes the result of the server check performed when the user finishes the enter of the\r
 +     * server URL.\r
 +     * \r
 +     * @param operation     Server check performed.\r
 +     * @param result        Result of the check.\r
 +     */\r
 +    private void onOcServerCheckFinish(OwnCloudServerCheckOperation operation, RemoteOperationResult result) {\r
 +        /// update status icon and text\r
 +        updateStatusIconAndText(result);\r
 +        updateConnStatus();\r
 +\r
 +        /// save result state\r
 +        mStatusCorrect = result.isSuccess();\r
 +        mIsSslConn = (result.getCode() == ResultCode.OK_SSL);\r
 +        \r
 +        /// very special case (TODO: move to a common place for all the remote operations)\r
 +        if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {\r
 +            mLastSslUntrustedServerResult = result;\r
 +            showDialog(DIALOG_SSL_VALIDATOR); \r
 +        }\r
 +        \r
 +        /// update the visibility of the 'retry connection' button\r
 +        if (!mStatusCorrect)\r
 +            mRefreshButton.setVisibility(View.VISIBLE);\r
 +        else\r
 +            mRefreshButton.setVisibility(View.INVISIBLE);\r
 +        \r
 +        /// retrieve discovered version and normalize server URL\r
 +        mDiscoveredVersion = operation.getDiscoveredVersion();\r
 +        mHostBaseUrl = mHostUrlInput.getText().toString().trim();\r
 +        if (!mHostBaseUrl.toLowerCase().startsWith("http://") &&\r
 +            !mHostBaseUrl.toLowerCase().startsWith("https://")) {\r
 +            \r
 +            if (mIsSslConn) {\r
 +                mHostBaseUrl = "https://" + mHostBaseUrl;\r
 +            } else {\r
 +                mHostBaseUrl = "http://" + mHostBaseUrl;\r
 +            }\r
 +            \r
 +        }\r
 +        if (mHostBaseUrl.endsWith("/"))\r
 +            mHostBaseUrl = mHostBaseUrl.substring(0, mHostBaseUrl.length() - 1);\r
 +        \r
 +        /// allow or not the user try to access the server\r
 +        mOkButton.setEnabled(mStatusCorrect);\r
 +    }\r
 +\r
 +\r
 +    /**\r
 +     * Chooses the right icon and text to show to the user for the received operation result.\r
 +     * \r
 +     * @param result    Result of a remote operation performed in this activity\r
 +     */\r
 +    private void updateStatusIconAndText(RemoteOperationResult result) {\r
 +        mStatusText = mStatusIcon = 0;\r
 +\r
 +        switch (result.getCode()) {\r
 +        case OK_SSL:\r
 +            mStatusIcon = android.R.drawable.ic_secure;\r
 +            mStatusText = R.string.auth_secure_connection;\r
 +            break;\r
 +            \r
 +        case OK_NO_SSL:\r
 +        case OK:\r
 +            if (mHostUrlInput.getText().toString().trim().toLowerCase().startsWith("http://") ) {\r
 +                mStatusText = R.string.auth_connection_established;\r
 +                mStatusIcon = R.drawable.ic_ok;\r
 +            } else {\r
 +                mStatusText = R.string.auth_nossl_plain_ok_title;\r
 +                mStatusIcon = android.R.drawable.ic_partial_secure;\r
 +            }\r
 +            break;\r
 +            \r
 +        case SSL_RECOVERABLE_PEER_UNVERIFIED:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_ssl_unverified_server_title;\r
 +            break;\r
 +                \r
 +        case BAD_OC_VERSION:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_bad_oc_version_title;\r
 +            break;\r
 +        case WRONG_CONNECTION:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_wrong_connection_title;\r
 +            break;\r
 +        case TIMEOUT:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_timeout_title;\r
 +            break;\r
 +        case INCORRECT_ADDRESS:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_incorrect_address_title;\r
 +            break;\r
 +            \r
 +        case SSL_ERROR:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_ssl_general_error_title;\r
 +            break;\r
 +            \r
 +        case UNAUTHORIZED:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_unauthorized;\r
 +            break;\r
 +        case HOST_NOT_AVAILABLE:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_unknown_host_title;\r
 +            break;\r
 +        case NO_NETWORK_CONNECTION:\r
 +            mStatusIcon = R.drawable.no_network;\r
 +            mStatusText = R.string.auth_no_net_conn_title;\r
 +            break;\r
 +        case INSTANCE_NOT_CONFIGURED:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_not_configured_title;\r
 +            break;\r
 +        case FILE_NOT_FOUND:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_incorrect_path_title;\r
 +            break;\r
 +        case OAUTH2_ERROR:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_oauth_error;\r
 +            break;\r
 +        case OAUTH2_ERROR_ACCESS_DENIED:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_oauth_error_access_denied;\r
 +            break;\r
 +        case UNHANDLED_HTTP_CODE:\r
 +        case UNKNOWN_ERROR:\r
 +            mStatusIcon = R.drawable.common_error;\r
 +            mStatusText = R.string.auth_unknown_error_title;\r
 +            break;\r
 +            \r
 +        default:\r
 +            break;\r
 +        }\r
 +    }\r
 +\r
 +\r
 +    /**\r
 +     * Processes the result of the request for and access token send \r
 +     * to an OAuth authorization server.\r
 +     * \r
 +     * @param operation     Operation performed requesting the access token.\r
 +     * @param result        Result of the operation.\r
 +     */\r
 +    private void onGetOAuthAccessTokenFinish(OAuth2GetAccessToken operation, RemoteOperationResult result) {\r
 +        try {\r
 +            dismissDialog(DIALOG_OAUTH2_LOGIN_PROGRESS);\r
 +        } catch (IllegalArgumentException e) {\r
 +            // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens\r
 +        }\r
 +\r
 +        String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, true);\r
 +        if (result.isSuccess() && webdav_path != null) {\r
 +            /// be gentle with the user\r
 +            showDialog(DIALOG_LOGIN_PROGRESS);\r
 +            \r
 +            /// time to test the retrieved access token on the ownCloud server\r
 +            mOAuthAccessToken = ((OAuth2GetAccessToken)operation).getResultTokenMap().get(OAuth2Constants.KEY_ACCESS_TOKEN);\r
-             Log.d(TAG, "Access failed: " + result.getLogMessage());\r
++            Log_OC.d(TAG, "Got ACCESS TOKEN: " + mOAuthAccessToken);\r
 +            mAuthCheckOperation = new ExistenceCheckOperation("", this, false);\r
 +            WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this);\r
 +            client.setBearerCredentials(mOAuthAccessToken);\r
 +            mAuthCheckOperation.execute(client, this, mHandler);\r
 +            \r
 +        } else {\r
 +            updateStatusIconAndText(result);\r
 +            updateAuthStatus();\r
-             Log.d(TAG, "Successful access - time to save the account");\r
++            Log_OC.d(TAG, "Access failed: " + result.getLogMessage());\r
 +        }\r
 +    }\r
 +\r
 +    \r
 +    /**\r
 +     * Processes the result of the access check performed to try the user credentials.\r
 +     * \r
 +     * Creates a new account through the AccountManager.\r
 +     * \r
 +     * @param operation     Access check performed.\r
 +     * @param result        Result of the operation.\r
 +     */\r
 +    private void onAuthorizationCheckFinish(ExistenceCheckOperation operation, RemoteOperationResult result) {\r
 +        try {\r
 +            dismissDialog(DIALOG_LOGIN_PROGRESS);\r
 +        } catch (IllegalArgumentException e) {\r
 +            // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens\r
 +        }\r
 +        \r
 +        if (result.isSuccess()) {\r
-             Log.d(TAG, "Access failed: " + result.getLogMessage());\r
++            Log_OC.d(TAG, "Successful access - time to save the account");\r
 +\r
 +            if (mAction == ACTION_CREATE) {\r
 +                createAccount();\r
 +                \r
 +            } else {\r
 +                updateToken();\r
 +            }\r
 +            \r
 +            finish();\r
 +            \r
 +        } else {\r
 +            updateStatusIconAndText(result);\r
 +            updateAuthStatus();\r
-             Log.e(TAG, "Incorrect dialog called with id = " + id);\r
++            Log_OC.d(TAG, "Access failed: " + result.getLogMessage());\r
 +        }\r
 +    }\r
 +\r
 +    \r
 +    /**\r
 +     * Sets the proper response to get that the Account Authenticator that started this activity saves \r
 +     * a new authorization token for mAccount.\r
 +     */\r
 +    private void updateToken() {\r
 +        Bundle response = new Bundle();\r
 +        response.putString(AccountManager.KEY_ACCOUNT_NAME, mAccount.name);\r
 +        response.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccount.type);\r
 +        boolean isOAuth = mOAuth2Check.isChecked();\r
 +        if (isOAuth) {\r
 +            response.putString(AccountManager.KEY_AUTHTOKEN, mOAuthAccessToken);\r
 +            // the next line is necessary; by now, notifications are calling directly to the AuthenticatorActivity to update, without AccountManager intervention\r
 +            mAccountMgr.setAuthToken(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, mOAuthAccessToken);\r
 +        } else {\r
 +            response.putString(AccountManager.KEY_AUTHTOKEN, mPasswordInput.getText().toString());\r
 +            mAccountMgr.setPassword(mAccount, mPasswordInput.getText().toString());\r
 +        }\r
 +        setAccountAuthenticatorResult(response);\r
 +    }\r
 +\r
 +\r
 +    /**\r
 +     * Creates a new account through the Account Authenticator that started this activity. \r
 +     * \r
 +     * This makes the account permanent.\r
 +     * \r
 +     * TODO Decide how to name the OAuth accounts\r
 +     */\r
 +    private void createAccount() {\r
 +        /// create and save new ownCloud account\r
 +        boolean isOAuth = mOAuth2Check.isChecked();\r
 +        \r
 +        Uri uri = Uri.parse(mHostBaseUrl);\r
 +        String username = mUsernameInput.getText().toString().trim();\r
 +        if (isOAuth) {\r
 +            username = "OAuth_user" + (new java.util.Random(System.currentTimeMillis())).nextLong();\r
 +        }            \r
 +        String accountName = username + "@" + uri.getHost();\r
 +        if (uri.getPort() >= 0) {\r
 +            accountName += ":" + uri.getPort();\r
 +        }\r
 +        mAccount = new Account(accountName, AccountAuthenticator.ACCOUNT_TYPE);\r
 +        if (isOAuth) {\r
 +            mAccountMgr.addAccountExplicitly(mAccount, "", null);  // with our implementation, the password is never input in the app\r
 +        } else {\r
 +            mAccountMgr.addAccountExplicitly(mAccount, mPasswordInput.getText().toString(), null);\r
 +        }\r
 +\r
 +        /// add the new account as default in preferences, if there is none already\r
 +        Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this);\r
 +        if (defaultAccount == null) {\r
 +            SharedPreferences.Editor editor = PreferenceManager\r
 +                    .getDefaultSharedPreferences(this).edit();\r
 +            editor.putString("select_oc_account", accountName);\r
 +            editor.commit();\r
 +        }\r
 +\r
 +        /// prepare result to return to the Authenticator\r
 +        //  TODO check again what the Authenticator makes with it; probably has the same effect as addAccountExplicitly, but it's not well done\r
 +        final Intent intent = new Intent();       \r
 +        intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE,    AccountAuthenticator.ACCOUNT_TYPE);\r
 +        intent.putExtra(AccountManager.KEY_ACCOUNT_NAME,    mAccount.name);\r
 +        if (!isOAuth)\r
 +            intent.putExtra(AccountManager.KEY_AUTHTOKEN,   AccountAuthenticator.ACCOUNT_TYPE); // TODO check this; not sure it's right; maybe\r
 +        intent.putExtra(AccountManager.KEY_USERDATA,        username);\r
 +        if (isOAuth) {\r
 +            mAccountMgr.setAuthToken(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, mOAuthAccessToken);\r
 +        }\r
 +        /// add user data to the new account; TODO probably can be done in the last parameter addAccountExplicitly, or in KEY_USERDATA\r
 +        mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION,    mDiscoveredVersion.toString());\r
 +        mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL,   mHostBaseUrl);\r
 +        if (isOAuth)\r
 +            mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_OAUTH2, "TRUE");  // TODO this flag should be unnecessary\r
 +    \r
 +        setAccountAuthenticatorResult(intent.getExtras());\r
 +        setResult(RESULT_OK, intent);\r
 +        \r
 +        /// immediately request for the synchronization of the new account\r
 +        Bundle bundle = new Bundle();\r
 +        bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);\r
 +        ContentResolver.requestSync(mAccount, AccountAuthenticator.AUTHORITY, bundle);\r
 +    }\r
 +\r
 +\r
 +    /**\r
 +     * {@inheritDoc}\r
 +     * \r
 +     * Necessary to update the contents of the SSL Dialog\r
 +     * \r
 +     * TODO move to some common place for all possible untrusted SSL failures\r
 +     */\r
 +    @Override\r
 +    protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {\r
 +        switch (id) {\r
 +        case DIALOG_LOGIN_PROGRESS:\r
 +        case DIALOG_CERT_NOT_SAVED:\r
 +        case DIALOG_OAUTH2_LOGIN_PROGRESS:\r
 +            break;\r
 +        case DIALOG_SSL_VALIDATOR: {\r
 +            ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);\r
 +            break;\r
 +        }\r
 +        default:\r
-                             Log.i(TAG, "Login canceled");\r
++            Log_OC.e(TAG, "Incorrect dialog called with id = " + id);\r
 +        }\r
 +    }\r
 +\r
 +    \r
 +    /**\r
 +     * {@inheritDoc}\r
 +     */\r
 +    @Override\r
 +    protected Dialog onCreateDialog(int id) {\r
 +        Dialog dialog = null;\r
 +        switch (id) {\r
 +        case DIALOG_LOGIN_PROGRESS: {\r
 +            /// simple progress dialog\r
 +            ProgressDialog working_dialog = new ProgressDialog(this);\r
 +            working_dialog.setMessage(getResources().getString(R.string.auth_trying_to_login));\r
 +            working_dialog.setIndeterminate(true);\r
 +            working_dialog.setCancelable(true);\r
 +            working_dialog\r
 +                    .setOnCancelListener(new DialogInterface.OnCancelListener() {\r
 +                        @Override\r
 +                        public void onCancel(DialogInterface dialog) {\r
 +                            /// TODO study if this is enough\r
-                     Log.i(TAG, "Login canceled");\r
++                            Log_OC.i(TAG, "Login canceled");\r
 +                            if (mOperationThread != null) {\r
 +                                mOperationThread.interrupt();\r
 +                                finish();\r
 +                            }\r
 +                        }\r
 +                    });\r
 +            dialog = working_dialog;\r
 +            break;\r
 +        }\r
 +        case DIALOG_OAUTH2_LOGIN_PROGRESS: {\r
 +            ProgressDialog working_dialog = new ProgressDialog(this);\r
 +            working_dialog.setMessage(String.format("Getting authorization")); \r
 +            working_dialog.setIndeterminate(true);\r
 +            working_dialog.setCancelable(true);\r
 +            working_dialog\r
 +            .setOnCancelListener(new DialogInterface.OnCancelListener() {\r
 +                @Override\r
 +                public void onCancel(DialogInterface dialog) {\r
-             Log.e(TAG, "Incorrect dialog called with id = " + id);\r
++                    Log_OC.i(TAG, "Login canceled");\r
 +                    finish();\r
 +                }\r
 +            });\r
 +            dialog = working_dialog;\r
 +            break;\r
 +        }\r
 +        case DIALOG_SSL_VALIDATOR: {\r
 +            /// TODO start to use new dialog interface, at least for this (it is a FragmentDialog already)\r
 +            dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);\r
 +            break;\r
 +        }\r
 +        case DIALOG_CERT_NOT_SAVED: {\r
 +            AlertDialog.Builder builder = new AlertDialog.Builder(this);\r
 +            builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));\r
 +            builder.setCancelable(false);\r
 +            builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {\r
 +                    @Override\r
 +                    public void onClick(DialogInterface dialog, int which) {\r
 +                        dialog.dismiss();\r
 +                    };\r
 +                });\r
 +            dialog = builder.create();\r
 +            break;\r
 +        }\r
 +        default:\r
++            Log_OC.e(TAG, "Incorrect dialog called with id = " + id);\r
 +        }\r
 +        return dialog;\r
 +    }\r
 +\r
 +    \r
 +    /**\r
 +     * Starts and activity to open the 'new account' page in the ownCloud web site\r
 +     * \r
 +     * @param view      'Account register' button\r
 +     */\r
 +    public void onRegisterClick(View view) {\r
 +        Intent register = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_account_register)));\r
 +        setResult(RESULT_CANCELED);\r
 +        startActivity(register);\r
 +    }\r
 +\r
 +    \r
 +    /**\r
 +     * Updates the content and visibility state of the icon and text associated\r
 +     * to the last check on the ownCloud server.\r
 +     */\r
 +    private void updateConnStatus() {\r
 +        ImageView iv = (ImageView) findViewById(R.id.action_indicator);\r
 +        TextView tv = (TextView) findViewById(R.id.status_text);\r
 +\r
 +        if (mStatusIcon == 0 && mStatusText == 0) {\r
 +            iv.setVisibility(View.INVISIBLE);\r
 +            tv.setVisibility(View.INVISIBLE);\r
 +        } else {\r
 +            iv.setImageResource(mStatusIcon);\r
 +            tv.setText(mStatusText);\r
 +            iv.setVisibility(View.VISIBLE);\r
 +            tv.setVisibility(View.VISIBLE);\r
 +        }\r
 +    }\r
 +    \r
 +    \r
 +    /**\r
 +     * Updates the content and visibility state of the icon and text associated\r
 +     * to the interactions with the OAuth authorization server.\r
 +     */\r
 +    private void updateAuthStatus() {\r
 +        if (mStatusIcon == 0 && mStatusText == 0) {\r
 +            mAuthStatusLayout.setVisibility(View.INVISIBLE);\r
 +        } else {\r
 +            mAuthStatusLayout.setText(mStatusText);\r
 +            mAuthStatusLayout.setCompoundDrawablesWithIntrinsicBounds(mStatusIcon, 0, 0, 0);\r
 +            mAuthStatusLayout.setVisibility(View.VISIBLE);\r
 +        }\r
 +    }     \r
 +\r
 +    \r
 +    /**\r
 +     * Called when the refresh button in the input field for ownCloud host is clicked.\r
 +     * \r
 +     * Performs a new check on the URL in the input field.\r
 +     * \r
 +     * @param view      Refresh 'button'\r
 +     */\r
 +    public void onRefreshClick(View view) {\r
 +        onFocusChange(mRefreshButton, false);\r
 +    }\r
 +    \r
 +    \r
 +    /**\r
 +     * Called when the eye icon in the password field is clicked.\r
 +     * \r
 +     * Toggles the visibility of the password in the field. \r
 +     * \r
 +     * @param view      'View password' 'button'\r
 +     */\r
 +    public void onViewPasswordClick(View view) {\r
 +        int selectionStart = mPasswordInput.getSelectionStart();\r
 +        int selectionEnd = mPasswordInput.getSelectionEnd();\r
 +        int input_type = mPasswordInput.getInputType();\r
 +        if ((input_type & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {\r
 +            input_type = InputType.TYPE_CLASS_TEXT\r
 +                    | InputType.TYPE_TEXT_VARIATION_PASSWORD;\r
 +        } else {\r
 +            input_type = InputType.TYPE_CLASS_TEXT\r
 +                    | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;\r
 +        }\r
 +        mPasswordInput.setInputType(input_type);\r
 +        mPasswordInput.setSelection(selectionStart, selectionEnd);\r
 +    }    \r
 +    \r
 +    \r
 +    /**\r
 +     * Called when the checkbox for OAuth authorization is clicked.\r
 +     * \r
 +     * Hides or shows the input fields for user & password. \r
 +     * \r
 +     * @param view      'View password' 'button'\r
 +     */\r
 +    public void onCheckClick(View view) {\r
 +        CheckBox oAuth2Check = (CheckBox)view;      \r
 +        changeViewByOAuth2Check(oAuth2Check.isChecked());\r
 +\r
 +    }\r
 +    \r
 +    /**\r
 +     * Changes the visibility of input elements depending upon the kind of authorization\r
 +     * chosen by the user: basic or OAuth\r
 +     * \r
 +     * @param checked       'True' when OAuth is selected.\r
 +     */\r
 +    public void changeViewByOAuth2Check(Boolean checked) {\r
 +        \r
 +        if (checked) {\r
 +            mOAuthAuthEndpointText.setVisibility(View.VISIBLE);\r
 +            mOAuthTokenEndpointText.setVisibility(View.VISIBLE);\r
 +            mUsernameInput.setVisibility(View.GONE);\r
 +            mPasswordInput.setVisibility(View.GONE);\r
 +            mViewPasswordButton.setVisibility(View.GONE);\r
 +        } else {\r
 +            mOAuthAuthEndpointText.setVisibility(View.GONE);\r
 +            mOAuthTokenEndpointText.setVisibility(View.GONE);\r
 +            mUsernameInput.setVisibility(View.VISIBLE);\r
 +            mPasswordInput.setVisibility(View.VISIBLE);\r
 +            mViewPasswordButton.setVisibility(View.INVISIBLE);\r
 +        }     \r
 +\r
 +    }    \r
 +    \r
 +    /**\r
 +     * Called from SslValidatorDialog when a new server certificate was correctly saved.\r
 +     */\r
 +    public void onSavedCertificate() {\r
 +        mOperationThread = mOcServerChkOperation.retry(this, mHandler);                \r
 +    }\r
 +\r
 +    /**\r
 +     * Called from SslValidatorDialog when a new server certificate could not be saved \r
 +     * when the user requested it.\r
 +     */\r
 +    @Override\r
 +    public void onFailedSavingCertificate() {\r
 +        showDialog(DIALOG_CERT_NOT_SAVED);\r
 +    }\r
 +\r
 +}\r
index 227accb,0000000..f96b627
mode 100644,000000..100644
--- /dev/null
@@@ -1,54 -1,0 +1,53 @@@
-  *   it under the terms of the GNU General Public License as published by
-  *   the Free Software Foundation, either version 2 of the License, or
-  *   (at your option) any later version.
 +/* 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";
 +    
 +}
@@@ -40,7 -40,7 +40,6 @@@ import android.content.OperationApplica
  import android.database.Cursor;
  import android.net.Uri;
  import android.os.RemoteException;
--import android.util.Log;
  
  public class FileDataStorageManager implements DataStorageManager {
  
- /* ownCloud Android client application\r
-  *   Copyright (C) 2011-2012  Bartek Przybylski\r
-  *\r
-  *   This program is free software: you can redistribute it and/or modify\r
-  *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 2 of the License, or\r
-  *   (at your option) any later version.\r
-  *\r
-  *   This program is distributed in the hope that it will be useful,\r
-  *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-  *   GNU General Public License for more details.\r
-  *\r
-  *   You should have received a copy of the GNU General Public License\r
-  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
-  *\r
-  */\r
- package com.owncloud.android.db;\r
\r
- import android.content.ContentValues;\r
- import android.content.Context;\r
- import android.database.Cursor;\r
- import android.database.sqlite.SQLiteDatabase;\r
- import android.database.sqlite.SQLiteOpenHelper;\r
\r
- /**\r
-  * Custom database helper for ownCloud\r
-  * \r
-  * @author Bartek Przybylski\r
-  * \r
-  */\r
- public class DbHandler {\r
-     private SQLiteDatabase mDB;\r
-     private OpenerHelper mHelper;\r
-     private final String mDatabaseName = "ownCloud";\r
-     private final int mDatabaseVersion = 1;\r
-     \r
-     private final String TABLE_INSTANT_UPLOAD = "instant_upload";\r
\r
-     public DbHandler(Context context) {\r
-         mHelper = new OpenerHelper(context);\r
-         mDB = mHelper.getWritableDatabase();\r
-     }\r
\r
-     public void close() {\r
-         mDB.close();\r
-     }\r
\r
-     public boolean putFileForLater(String filepath, String account) {\r
-         ContentValues cv = new ContentValues();\r
-         cv.put("path", filepath);\r
-         cv.put("account", account);\r
-         return mDB.insert(TABLE_INSTANT_UPLOAD, null, cv) != -1;\r
-     }\r
-     \r
-     public Cursor getAwaitingFiles() {\r
-         return mDB.query(TABLE_INSTANT_UPLOAD, null, null, null, null, null, null);\r
-     }\r
-     \r
-     public void clearFiles() {\r
-         mDB.delete(TABLE_INSTANT_UPLOAD, null, null);\r
-     }\r
-     \r
-     /**\r
-      * \r
-      * @param localPath\r
-      * @param accountName\r
-      * @return true when one or more pendin files was removed\r
-      */\r
-     public boolean removeIUPendingFile(String localPath, String accountName) {\r
-         return mDB.delete(TABLE_INSTANT_UPLOAD,\r
-                           "path = ?",\r
-                           new String[]{ localPath }) != 0;\r
-         \r
-     }\r
-     \r
-     private class OpenerHelper extends SQLiteOpenHelper {\r
-         public OpenerHelper(Context context) {\r
-             super(context, mDatabaseName, null, mDatabaseVersion);\r
-         }\r
\r
-         @Override\r
-         public void onCreate(SQLiteDatabase db) {\r
-             db.execSQL("CREATE TABLE " + TABLE_INSTANT_UPLOAD + " ("\r
-                       + " _id INTEGER PRIMARY KEY, "\r
-                       + " path TEXT,"\r
-                       + " account TEXT);");\r
-         }\r
\r
-         @Override\r
-         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\r
-         }\r
-     }\r
- }\r
+ /* ownCloud Android client application
+  *   Copyright (C) 2011-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.db;
+ import com.owncloud.android.Log_OC;
+ import android.content.ContentValues;
+ 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
+  * 
+  * @author Bartek Przybylski
+  * 
+  */
+ public class DbHandler {
+     private SQLiteDatabase mDB;
+     private OpenerHelper mHelper;
+     private final String mDatabaseName = "ownCloud";
+     private final int mDatabaseVersion = 3;
+     private final String TABLE_INSTANT_UPLOAD = "instant_upload";
+     public static final int UPLOAD_STATUS_UPLOAD_LATER = 0;
+     public static final int UPLOAD_STATUS_UPLOAD_FAILED = 1;
+     public DbHandler(Context context) {
+         mHelper = new OpenerHelper(context);
+         mDB = mHelper.getWritableDatabase();
+     }
+     public void close() {
+         mDB.close();
+     }
+     public boolean putFileForLater(String filepath, String account, String message) {
+         ContentValues cv = new ContentValues();
+         cv.put("path", filepath);
+         cv.put("account", account);
+         cv.put("attempt", UPLOAD_STATUS_UPLOAD_LATER);
+         cv.put("message", message);
+         long result = mDB.insert(TABLE_INSTANT_UPLOAD, null, cv);
+         Log_OC.d(TABLE_INSTANT_UPLOAD, "putFileForLater returns with: " + result + " for file: " + filepath);
+         return result != -1;
+     }
+     public int updateFileState(String filepath, Integer status, String message) {
+         ContentValues cv = new ContentValues();
+         cv.put("attempt", status);
+         cv.put("message", message);
+         int result = mDB.update(TABLE_INSTANT_UPLOAD, cv, "path=?", new String[] { filepath });
+         Log_OC.d(TABLE_INSTANT_UPLOAD, "updateFileState returns with: " + result + " for file: " + filepath);
+         return result;
+     }
+     public Cursor getAwaitingFiles() {
+         return mDB.query(TABLE_INSTANT_UPLOAD, null, "attempt=" + UPLOAD_STATUS_UPLOAD_LATER, null, null, null, null);
+     }
+     public Cursor getFailedFiles() {
+         return mDB.query(TABLE_INSTANT_UPLOAD, null, "attempt>" + UPLOAD_STATUS_UPLOAD_LATER, null, null, null, null);
+     }
+     public void clearFiles() {
+         mDB.delete(TABLE_INSTANT_UPLOAD, null, null);
+     }
+     /**
+      * 
+      * @param localPath
+      * @return true when one or more pending files was removed
+      */
+     public boolean removeIUPendingFile(String localPath) {
+         long result = mDB.delete(TABLE_INSTANT_UPLOAD, "path = ?", new String[] { localPath });
+         Log_OC.d(TABLE_INSTANT_UPLOAD, "delete returns with: " + result + " for file: " + localPath);
+         return result != 0;
+     }
+     private class OpenerHelper extends SQLiteOpenHelper {
+         public OpenerHelper(Context context) {
+             super(context, mDatabaseName, null, mDatabaseVersion);
+         }
+         @Override
+         public void onCreate(SQLiteDatabase db) {
+             db.execSQL("CREATE TABLE " + TABLE_INSTANT_UPLOAD + " (" + " _id INTEGER PRIMARY KEY, " + " path TEXT,"
+                     + " account TEXT,attempt INTEGER,message TEXT);");
+         }
+         @Override
+         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+             if (oldVersion < 2) {
+                 db.execSQL("ALTER TABLE " + TABLE_INSTANT_UPLOAD + " ADD COLUMN attempt INTEGER;");
+             }
+             db.execSQL("ALTER TABLE " + TABLE_INSTANT_UPLOAD + " ADD COLUMN message TEXT;");
+         }
+     }
+ }
@@@ -23,7 -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;
@@@ -35,7 -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 {
@@@ -24,7 -24,7 +24,6 @@@ import com.owncloud.android.files.servi
  import android.content.BroadcastReceiver;
  import android.content.Context;
  import android.content.Intent;
--import android.util.Log;
  
  public class BootupBroadcastReceiver extends BroadcastReceiver {
  
@@@ -36,22 -30,24 +35,20 @@@ import android.net.ConnectivityManager
  import android.net.NetworkInfo.State;
  import android.preference.PreferenceManager;
  import android.provider.MediaStore.Images.Media;
- import android.util.Log;
  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 {
  
-     public static String INSTANT_UPLOAD_DIR = "/InstantUpload/";
      private static String TAG = "PhotoTakenBroadcastReceiver";
-     private static final String[] CONTENT_PROJECTION = { Media.DATA,
-                                                          Media.DISPLAY_NAME,
-                                                          Media.MIME_TYPE,
-                                                          Media.SIZE };
+     private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE };
      private static String NEW_PHOTO_ACTION = "com.android.camera.NEW_PICTURE";
-     
      @Override
      public void onReceive(Context context, Intent intent) {
-         Log.d(TAG, "Received: " + intent.getAction());
+         Log_OC.d(TAG, "Received: " + intent.getAction());
          if (intent.getAction().equals(android.net.ConnectivityManager.CONNECTIVITY_ACTION)) {
              handleConnectivityAction(context, intent);
          } else if (intent.getAction().equals(NEW_PHOTO_ACTION)) {
@@@ -21,8 -20,10 +20,9 @@@ package com.owncloud.android.files
  
  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;
@@@ -33,7 -35,7 +33,6 @@@ 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 {
  
- /* ownCloud Android client application\r
-  *   Copyright (C) 2012 Bartek Przybylski\r
-  *   Copyright (C) 2012-2013 ownCloud Inc.\r
-  *\r
-  *   This program is free software: you can redistribute it and/or modify\r
-  *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 2 of the License, or\r
-  *   (at your option) any later version.\r
-  *\r
-  *   This program is distributed in the hope that it will be useful,\r
-  *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-  *   GNU General Public License for more details.\r
-  *\r
-  *   You should have received a copy of the GNU General Public License\r
-  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
-  *\r
-  */\r
\r
- package com.owncloud.android.files.services;\r
\r
- import java.io.File;\r
- import java.io.IOException;\r
- import java.util.AbstractList;\r
- import java.util.Iterator;\r
- import java.util.Vector;\r
- import java.util.concurrent.ConcurrentHashMap;\r
- import java.util.concurrent.ConcurrentMap;\r
\r
- import com.owncloud.android.authentication.AuthenticatorActivity;\r
- import com.owncloud.android.datamodel.FileDataStorageManager;\r
- import com.owncloud.android.datamodel.OCFile;\r
- import eu.alefzero.webdav.OnDatatransferProgressListener;\r
\r
- import com.owncloud.android.network.OwnCloudClientUtils;\r
- import com.owncloud.android.operations.DownloadFileOperation;\r
- import com.owncloud.android.operations.RemoteOperationResult;\r
- import com.owncloud.android.operations.RemoteOperationResult.ResultCode;\r
- import com.owncloud.android.ui.activity.FileDetailActivity;\r
- import com.owncloud.android.ui.fragment.FileDetailFragment;\r
\r
- import android.accounts.Account;\r
- import android.accounts.AccountsException;\r
- import android.app.Notification;\r
- import android.app.NotificationManager;\r
- import android.app.PendingIntent;\r
- import android.app.Service;\r
- import android.content.Intent;\r
- import android.os.Binder;\r
- import android.os.Handler;\r
- import android.os.HandlerThread;\r
- import android.os.IBinder;\r
- import android.os.Looper;\r
- import android.os.Message;\r
- import android.os.Process;\r
- import android.util.Log;\r
- import android.widget.RemoteViews;\r
\r
- import com.owncloud.android.R;\r
- import eu.alefzero.webdav.WebdavClient;\r
\r
- public class FileDownloader extends Service implements OnDatatransferProgressListener {\r
-     \r
-     public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
-     public static final String EXTRA_FILE = "FILE";\r
-     \r
-     public static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED";\r
-     public static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH";\r
-     public static final String EXTRA_DOWNLOAD_RESULT = "RESULT";    \r
-     public static final String EXTRA_FILE_PATH = "FILE_PATH";\r
-     public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";\r
-     public static final String ACCOUNT_NAME = "ACCOUNT_NAME";\r
-     \r
-     private static final String TAG = "FileDownloader";\r
\r
-     private Looper mServiceLooper;\r
-     private ServiceHandler mServiceHandler;\r
-     private IBinder mBinder;\r
-     private WebdavClient mDownloadClient = null;\r
-     private Account mLastAccount = null;\r
-     private FileDataStorageManager mStorageManager;\r
-     \r
-     private ConcurrentMap<String, DownloadFileOperation> mPendingDownloads = new ConcurrentHashMap<String, DownloadFileOperation>();\r
-     private DownloadFileOperation mCurrentDownload = null;\r
-     \r
-     private NotificationManager mNotificationManager;\r
-     private Notification mNotification;\r
-     private int mLastPercent;\r
-     \r
-     \r
-     /**\r
-      * Builds a key for mPendingDownloads from the account and file to download\r
-      * \r
-      * @param account   Account where the file to download is stored\r
-      * @param file      File to download\r
-      */\r
-     private String buildRemoteName(Account account, OCFile file) {\r
-         return account.name + file.getRemotePath();\r
-     }\r
\r
-     \r
-     /**\r
-      * Service initialization\r
-      */\r
-     @Override\r
-     public void onCreate() {\r
-         super.onCreate();\r
-         mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);\r
-         HandlerThread thread = new HandlerThread("FileDownloaderThread",\r
-                 Process.THREAD_PRIORITY_BACKGROUND);\r
-         thread.start();\r
-         mServiceLooper = thread.getLooper();\r
-         mServiceHandler = new ServiceHandler(mServiceLooper, this);\r
-         mBinder = new FileDownloaderBinder();\r
-     }\r
\r
-     \r
-     /**\r
-      * Entry point to add one or several files to the queue of downloads.\r
-      * \r
-      * New downloads are added calling to startService(), resulting in a call to this method. This ensures the service will keep on working \r
-      * although the caller activity goes away.\r
-      */\r
-     @Override\r
-     public int onStartCommand(Intent intent, int flags, int startId) {\r
-         if (    !intent.hasExtra(EXTRA_ACCOUNT) ||\r
-                 !intent.hasExtra(EXTRA_FILE)\r
-                 /*!intent.hasExtra(EXTRA_FILE_PATH) ||\r
-                 !intent.hasExtra(EXTRA_REMOTE_PATH)*/\r
-            ) {\r
-             Log.e(TAG, "Not enough information provided in intent");\r
-             return START_NOT_STICKY;\r
-         }\r
-         Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);\r
-         OCFile file = intent.getParcelableExtra(EXTRA_FILE);\r
-         \r
-         AbstractList<String> requestedDownloads = new Vector<String>(); // dvelasco: now this always contains just one element, but that can change in a near future (download of multiple selection)\r
-         String downloadKey = buildRemoteName(account, file);\r
-         try {\r
-             DownloadFileOperation newDownload = new DownloadFileOperation(account, file); \r
-             mPendingDownloads.putIfAbsent(downloadKey, newDownload);\r
-             newDownload.addDatatransferProgressListener(this);\r
-             requestedDownloads.add(downloadKey);\r
-             sendBroadcastNewDownload(newDownload);\r
-             \r
-         } catch (IllegalArgumentException e) {\r
-             Log.e(TAG, "Not enough information provided in intent: " + e.getMessage());\r
-             return START_NOT_STICKY;\r
-         }\r
-         \r
-         if (requestedDownloads.size() > 0) {\r
-             Message msg = mServiceHandler.obtainMessage();\r
-             msg.arg1 = startId;\r
-             msg.obj = requestedDownloads;\r
-             mServiceHandler.sendMessage(msg);\r
-         }\r
\r
-         return START_NOT_STICKY;\r
-     }\r
-     \r
-     \r
-     /**\r
-      * Provides a binder object that clients can use to perform operations on the queue of downloads, excepting the addition of new files. \r
-      * \r
-      * Implemented to perform cancellation, pause and resume of existing downloads.\r
-      */\r
-     @Override\r
-     public IBinder onBind(Intent arg0) {\r
-         return mBinder;\r
-     }\r
\r
-     \r
-     /**\r
-      *  Binder to let client components to perform operations on the queue of downloads.\r
-      * \r
-      *  It provides by itself the available operations.\r
-      */\r
-     public class FileDownloaderBinder extends Binder {\r
-         \r
-         /**\r
-          * Cancels a pending or current download of a remote file.\r
-          * \r
-          * @param account       Owncloud account where the remote file is stored.\r
-          * @param file          A file in the queue of pending downloads\r
-          */\r
-         public void cancel(Account account, OCFile file) {\r
-             DownloadFileOperation download = null;\r
-             synchronized (mPendingDownloads) {\r
-                 download = mPendingDownloads.remove(buildRemoteName(account, file));\r
-             }\r
-             if (download != null) {\r
-                 download.cancel();\r
-             }\r
-         }\r
-         \r
-         \r
-         /**\r
-          * Returns True when the file described by 'file' in the ownCloud account 'account' is downloading or waiting to download.\r
-          * \r
-          * If 'file' is a directory, returns 'true' if some of its descendant files is downloading or waiting to download. \r
-          * \r
-          * @param account       Owncloud account where the remote file is stored.\r
-          * @param file          A file that could be in the queue of downloads.\r
-          */\r
-         public boolean isDownloading(Account account, OCFile file) {\r
-             if (account == null || file == null) return false;\r
-             String targetKey = buildRemoteName(account, file);\r
-             synchronized (mPendingDownloads) {\r
-                 if (file.isDirectory()) {\r
-                     // this can be slow if there are many downloads :(\r
-                     Iterator<String> it = mPendingDownloads.keySet().iterator();\r
-                     boolean found = false;\r
-                     while (it.hasNext() && !found) {\r
-                         found = it.next().startsWith(targetKey);\r
-                     }\r
-                     return found;\r
-                 } else {\r
-                     return (mPendingDownloads.containsKey(targetKey));\r
-                 }\r
-             }\r
-         }\r
-     }\r
-     \r
-     \r
-     /** \r
-      * Download worker. Performs the pending downloads in the order they were requested. \r
-      * \r
-      * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}. \r
-      */\r
-     private static class ServiceHandler extends Handler {\r
-         // don't make it a final class, and don't remove the static ; lint will warn about a possible memory leak\r
-         FileDownloader mService;\r
-         public ServiceHandler(Looper looper, FileDownloader service) {\r
-             super(looper);\r
-             if (service == null)\r
-                 throw new IllegalArgumentException("Received invalid NULL in parameter 'service'");\r
-             mService = service;\r
-         }\r
\r
-         @Override\r
-         public void handleMessage(Message msg) {\r
-             @SuppressWarnings("unchecked")\r
-             AbstractList<String> requestedDownloads = (AbstractList<String>) msg.obj;\r
-             if (msg.obj != null) {\r
-                 Iterator<String> it = requestedDownloads.iterator();\r
-                 while (it.hasNext()) {\r
-                     mService.downloadFile(it.next());\r
-                 }\r
-             }\r
-             mService.stopSelf(msg.arg1);\r
-         }\r
-     }\r
-     \r
-     \r
\r
-     /**\r
-      * Core download method: requests a file to download and stores it.\r
-      * \r
-      * @param downloadKey   Key to access the download to perform, contained in mPendingDownloads \r
-      */\r
-     private void downloadFile(String downloadKey) {\r
-         \r
-         synchronized(mPendingDownloads) {\r
-             mCurrentDownload = mPendingDownloads.get(downloadKey);\r
-         }\r
-         \r
-         if (mCurrentDownload != null) {\r
-             \r
-             notifyDownloadStart(mCurrentDownload);\r
\r
-             RemoteOperationResult downloadResult = null;\r
-             try {\r
-                 /// prepare client object to send the request to the ownCloud server\r
-                 if (mDownloadClient == null || !mLastAccount.equals(mCurrentDownload.getAccount())) {\r
-                     mLastAccount = mCurrentDownload.getAccount();\r
-                     mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());\r
-                     mDownloadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());\r
-                 }\r
\r
-                 /// perform the download\r
-                 if (downloadResult == null) {\r
-                     downloadResult = mCurrentDownload.execute(mDownloadClient);\r
-                 }\r
-                 if (downloadResult.isSuccess()) {\r
-                     saveDownloadedFile();\r
-                 }\r
-             \r
-             } catch (AccountsException e) {\r
-                 Log.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);\r
-                 downloadResult = new RemoteOperationResult(e);\r
-             } catch (IOException e) {\r
-                 Log.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);\r
-                 downloadResult = new RemoteOperationResult(e);\r
-                 \r
-             } finally {\r
-                 synchronized(mPendingDownloads) {\r
-                     mPendingDownloads.remove(downloadKey);\r
-                 }\r
-             }\r
\r
-             \r
-             /// notify result\r
-             notifyDownloadResult(mCurrentDownload, downloadResult);\r
-             \r
-             sendBroadcastDownloadFinished(mCurrentDownload, downloadResult);\r
-         }\r
-     }\r
\r
\r
-     /**\r
-      * Updates the OC File after a successful download.\r
-      */\r
-     private void saveDownloadedFile() {\r
-         OCFile file = mCurrentDownload.getFile();\r
-         long syncDate = System.currentTimeMillis();\r
-         file.setLastSyncDateForProperties(syncDate);\r
-         file.setLastSyncDateForData(syncDate);\r
-         file.setModificationTimestamp(mCurrentDownload.getModificationTimestamp());\r
-         file.setModificationTimestampAtLastSyncForData(mCurrentDownload.getModificationTimestamp());\r
-         // file.setEtag(mCurrentDownload.getEtag());    // TODO Etag, where available\r
-         file.setMimetype(mCurrentDownload.getMimeType());\r
-         file.setStoragePath(mCurrentDownload.getSavePath());\r
-         file.setFileLength((new File(mCurrentDownload.getSavePath()).length()));\r
-         mStorageManager.saveFile(file);\r
-     }\r
\r
\r
-     /**\r
-      * Creates a status notification to show the download progress\r
-      * \r
-      * @param download  Download operation starting.\r
-      */\r
-     private void notifyDownloadStart(DownloadFileOperation download) {\r
-         /// create status notification with a progress bar\r
-         mLastPercent = 0;\r
-         mNotification = new Notification(R.drawable.icon, getString(R.string.downloader_download_in_progress_ticker), System.currentTimeMillis());\r
-         mNotification.flags |= Notification.FLAG_ONGOING_EVENT;\r
-         mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbar_layout);\r
-         mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, download.getSize() < 0);\r
-         mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.downloader_download_in_progress_content), 0, new File(download.getSavePath()).getName()));\r
-         mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon);\r
-         \r
-         /// includes a pending intent in the notification showing the details view of the file\r
-         Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);\r
-         showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, download.getFile());\r
-         showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, download.getAccount());\r
-         showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
-         mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0);\r
-         \r
-         mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification);\r
-     }\r
\r
-     \r
-     /**\r
-      * Callback method to update the progress bar in the status notification.\r
-      */\r
-     @Override\r
-     public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileName) {\r
-         int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));\r
-         if (percent != mLastPercent) {\r
-           mNotification.contentView.setProgressBar(R.id.status_progress, 100, percent, totalToTransfer < 0);\r
-           String text = String.format(getString(R.string.downloader_download_in_progress_content), percent, fileName);\r
-           mNotification.contentView.setTextViewText(R.id.status_text, text);\r
-           mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification);\r
-         }\r
-         mLastPercent = percent;\r
-     }\r
-     \r
-     \r
-     /**\r
-      * Callback method to update the progress bar in the status notification (old version)\r
-      */\r
-     @Override\r
-     public void onTransferProgress(long progressRate) {\r
-         // NOTHING TO DO HERE ANYMORE\r
-     }\r
-     \r
\r
-     /**\r
-      * Updates the status notification with the result of a download operation.\r
-      * \r
-      * @param downloadResult    Result of the download operation.\r
-      * @param download          Finished download operation\r
-      */\r
-     private void notifyDownloadResult(DownloadFileOperation download, RemoteOperationResult downloadResult) {\r
-         mNotificationManager.cancel(R.string.downloader_download_in_progress_ticker);\r
-         if (!downloadResult.isCancelled()) {\r
-             int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker : R.string.downloader_download_failed_ticker;\r
-             int contentId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_content : R.string.downloader_download_failed_content;\r
-             Notification finalNotification = new Notification(R.drawable.icon, getString(tickerId), System.currentTimeMillis());\r
-             finalNotification.flags |= Notification.FLAG_AUTO_CANCEL;\r
-             boolean needsToUpdateCredentials = (downloadResult.getCode() == ResultCode.UNAUTHORIZED);\r
-             if (needsToUpdateCredentials) {\r
-                 // let the user update credentials with one click\r
-                 Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);\r
-                 updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, download.getAccount());\r
-                 updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);\r
-                 updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\r
-                 updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);\r
-                 updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);\r
-                 finalNotification.contentIntent = PendingIntent.getActivity(this, (int)System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT);\r
-                 finalNotification.setLatestEventInfo(   getApplicationContext(), \r
-                                                         getString(tickerId), \r
-                                                         String.format(getString(contentId), new File(download.getSavePath()).getName()),\r
-                                                         finalNotification.contentIntent);\r
-                 mDownloadClient = null;   // grant that future retries on the same account will get the fresh credentials\r
-                 \r
-             } else {\r
-                 // TODO put something smart in the contentIntent below\r
-                 finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);\r
-                 finalNotification.setLatestEventInfo(getApplicationContext(), getString(tickerId), String.format(getString(contentId), new File(download.getSavePath()).getName()), finalNotification.contentIntent);\r
-             }\r
-             mNotificationManager.notify(tickerId, finalNotification);\r
-         }\r
-     }\r
-     \r
-     \r
-     /**\r
-      * Sends a broadcast when a download finishes in order to the interested activities can update their view\r
-      * \r
-      * @param download          Finished download operation\r
-      * @param downloadResult    Result of the download operation\r
-      */\r
-     private void sendBroadcastDownloadFinished(DownloadFileOperation download, RemoteOperationResult downloadResult) {\r
-         Intent end = new Intent(DOWNLOAD_FINISH_MESSAGE);\r
-         end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess());\r
-         end.putExtra(ACCOUNT_NAME, download.getAccount().name);\r
-         end.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());\r
-         end.putExtra(EXTRA_FILE_PATH, download.getSavePath());\r
-         sendStickyBroadcast(end);\r
-     }\r
-     \r
-     \r
-     /**\r
-      * Sends a broadcast when a new download is added to the queue.\r
-      * \r
-      * @param download          Added download operation\r
-      */\r
-     private void sendBroadcastNewDownload(DownloadFileOperation download) {\r
-         Intent added = new Intent(DOWNLOAD_ADDED_MESSAGE);\r
-         /*added.putExtra(ACCOUNT_NAME, download.getAccount().name);\r
-         added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());*/\r
-         added.putExtra(EXTRA_FILE_PATH, download.getSavePath());\r
-         sendStickyBroadcast(added);\r
-     }\r
\r
- }\r
+ /* 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 java.io.IOException;
+ import java.util.AbstractList;
+ import java.util.HashMap;
+ import java.util.Iterator;
+ import java.util.Map;
+ 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;
+ 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;
+ import android.app.Service;
+ import android.content.Intent;
+ import android.os.Binder;
+ import android.os.Handler;
+ import android.os.HandlerThread;
+ import android.os.IBinder;
+ import android.os.Looper;
+ import android.os.Message;
+ import android.os.Process;
+ import android.widget.RemoteViews;
+ import com.owncloud.android.Log_OC;
+ import com.owncloud.android.R;
+ import eu.alefzero.webdav.WebdavClient;
+ public class FileDownloader extends Service implements OnDatatransferProgressListener {
+     
+     public static final String EXTRA_ACCOUNT = "ACCOUNT";
+     public static final String EXTRA_FILE = "FILE";
+     
+     public static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED";
+     public static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH";
+     public static final String EXTRA_DOWNLOAD_RESULT = "RESULT";    
+     public static final String EXTRA_FILE_PATH = "FILE_PATH";
+     public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";
+     public static final String ACCOUNT_NAME = "ACCOUNT_NAME";
+     
+     private static final String TAG = "FileDownloader";
+     private Looper mServiceLooper;
+     private ServiceHandler mServiceHandler;
+     private IBinder mBinder;
+     private WebdavClient mDownloadClient = null;
+     private Account mLastAccount = null;
+     private FileDataStorageManager mStorageManager;
+     
+     private ConcurrentMap<String, DownloadFileOperation> mPendingDownloads = new ConcurrentHashMap<String, DownloadFileOperation>();
+     private DownloadFileOperation mCurrentDownload = null;
+     
+     private NotificationManager mNotificationManager;
+     private Notification mNotification;
+     private int mLastPercent;
+     
+     
+     /**
+      * Builds a key for mPendingDownloads from the account and file to download
+      * 
+      * @param account   Account where the file to download is stored
+      * @param file      File to download
+      */
+     private String buildRemoteName(Account account, OCFile file) {
+         return account.name + file.getRemotePath();
+     }
+     
+     /**
+      * Service initialization
+      */
+     @Override
+     public void onCreate() {
+         super.onCreate();
+         mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+         HandlerThread thread = new HandlerThread("FileDownloaderThread",
+                 Process.THREAD_PRIORITY_BACKGROUND);
+         thread.start();
+         mServiceLooper = thread.getLooper();
+         mServiceHandler = new ServiceHandler(mServiceLooper, this);
+         mBinder = new FileDownloaderBinder();
+     }
 -    
+     /**
+      * Entry point to add one or several files to the queue of downloads.
+      * 
+      * New downloads are added calling to startService(), resulting in a call to this method. This ensures the service will keep on working 
+      * although the caller activity goes away.
+      */
+     @Override
+     public int onStartCommand(Intent intent, int flags, int startId) {
+         if (    !intent.hasExtra(EXTRA_ACCOUNT) ||
+                 !intent.hasExtra(EXTRA_FILE)
+                 /*!intent.hasExtra(EXTRA_FILE_PATH) ||
+                 !intent.hasExtra(EXTRA_REMOTE_PATH)*/
+            ) {
+             Log_OC.e(TAG, "Not enough information provided in intent");
+             return START_NOT_STICKY;
+         }
+         Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);
+         OCFile file = intent.getParcelableExtra(EXTRA_FILE);
+         
+         AbstractList<String> requestedDownloads = new Vector<String>(); // dvelasco: now this always contains just one element, but that can change in a near future (download of multiple selection)
+         String downloadKey = buildRemoteName(account, file);
+         try {
+             DownloadFileOperation newDownload = new DownloadFileOperation(account, file); 
+             mPendingDownloads.putIfAbsent(downloadKey, newDownload);
+             newDownload.addDatatransferProgressListener(this);
+             newDownload.addDatatransferProgressListener((FileDownloaderBinder)mBinder);
+             requestedDownloads.add(downloadKey);
+             sendBroadcastNewDownload(newDownload);
+             
+         } catch (IllegalArgumentException e) {
+             Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage());
+             return START_NOT_STICKY;
+         }
+         
+         if (requestedDownloads.size() > 0) {
+             Message msg = mServiceHandler.obtainMessage();
+             msg.arg1 = startId;
+             msg.obj = requestedDownloads;
+             mServiceHandler.sendMessage(msg);
+         }
+         return START_NOT_STICKY;
+     }
+     
+     
+     /**
+      * Provides a binder object that clients can use to perform operations on the queue of downloads, excepting the addition of new files. 
+      * 
+      * Implemented to perform cancellation, pause and resume of existing downloads.
+      */
+     @Override
+     public IBinder onBind(Intent arg0) {
+         return mBinder;
+     }
+     /**
+      * Called when ALL the bound clients were onbound.
+      */
+     @Override
+     public boolean onUnbind(Intent intent) {
+         ((FileDownloaderBinder)mBinder).clearListeners();
+         return false;   // not accepting rebinding (default behaviour)
+     }
+     
+     /**
+      *  Binder to let client components to perform operations on the queue of downloads.
+      * 
+      *  It provides by itself the available operations.
+      */
+     public class FileDownloaderBinder extends Binder implements OnDatatransferProgressListener {
+         
+         /** 
+          * Map of listeners that will be reported about progress of downloads from a {@link FileDownloaderBinder} instance 
+          */
+         private Map<String, OnDatatransferProgressListener> mBoundListeners = new HashMap<String, OnDatatransferProgressListener>();
+         
+         
+         /**
+          * Cancels a pending or current download of a remote file.
+          * 
+          * @param account       Owncloud account where the remote file is stored.
+          * @param file          A file in the queue of pending downloads
+          */
+         public void cancel(Account account, OCFile file) {
+             DownloadFileOperation download = null;
+             synchronized (mPendingDownloads) {
+                 download = mPendingDownloads.remove(buildRemoteName(account, file));
+             }
+             if (download != null) {
+                 download.cancel();
+             }
+         }
+         
+         
+         public void clearListeners() {
+             mBoundListeners.clear();
+         }
+         /**
+          * Returns True when the file described by 'file' in the ownCloud account 'account' is downloading or waiting to download.
+          * 
+          * If 'file' is a directory, returns 'true' if some of its descendant files is downloading or waiting to download. 
+          * 
+          * @param account       Owncloud account where the remote file is stored.
+          * @param file          A file that could be in the queue of downloads.
+          */
+         public boolean isDownloading(Account account, OCFile file) {
+             if (account == null || file == null) return false;
+             String targetKey = buildRemoteName(account, file);
+             synchronized (mPendingDownloads) {
+                 if (file.isDirectory()) {
+                     // this can be slow if there are many downloads :(
+                     Iterator<String> it = mPendingDownloads.keySet().iterator();
+                     boolean found = false;
+                     while (it.hasNext() && !found) {
+                         found = it.next().startsWith(targetKey);
+                     }
+                     return found;
+                 } else {
+                     return (mPendingDownloads.containsKey(targetKey));
+                 }
+             }
+         }
+         
+         /**
+          * Adds a listener interested in the progress of the download for a concrete file.
+          * 
+          * @param listener      Object to notify about progress of transfer.    
+          * @param account       ownCloud account holding the file of interest.
+          * @param file          {@link OCfile} of interest for listener. 
+          */
+         public void addDatatransferProgressListener (OnDatatransferProgressListener listener, Account account, OCFile file) {
+             if (account == null || file == null || listener == null) return;
+             String targetKey = buildRemoteName(account, file);
+             mBoundListeners.put(targetKey, listener);
+         }
+         
+         
 -        
+         /**
+          * Removes a listener interested in the progress of the download for a concrete file.
+          * 
+          * @param listener      Object to notify about progress of transfer.    
+          * @param account       ownCloud account holding the file of interest.
+          * @param file          {@link OCfile} of interest for listener. 
+          */
+         public void removeDatatransferProgressListener (OnDatatransferProgressListener listener, Account account, OCFile file) {
+             if (account == null || file == null || listener == null) return;
+             String targetKey = buildRemoteName(account, file);
+             if (mBoundListeners.get(targetKey) == listener) {
+                 mBoundListeners.remove(targetKey);
+             }
+         }
+         @Override
+         public void onTransferProgress(long progressRate) {
+             // old way, should not be in use any more
+         }
+         @Override
+         public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer,
+                 String fileName) {
+             String key = buildRemoteName(mCurrentDownload.getAccount(), mCurrentDownload.getFile());
+             OnDatatransferProgressListener boundListener = mBoundListeners.get(key);
+             if (boundListener != null) {
+                 boundListener.onTransferProgress(progressRate, totalTransferredSoFar, totalToTransfer, fileName);
+             }
+         }
+         
+     }
+     
+     
+     /** 
+      * Download worker. Performs the pending downloads in the order they were requested. 
+      * 
+      * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}. 
+      */
+     private static class ServiceHandler extends Handler {
+         // don't make it a final class, and don't remove the static ; lint will warn about a possible memory leak
+         FileDownloader mService;
+         public ServiceHandler(Looper looper, FileDownloader service) {
+             super(looper);
+             if (service == null)
+                 throw new IllegalArgumentException("Received invalid NULL in parameter 'service'");
+             mService = service;
+         }
+         @Override
+         public void handleMessage(Message msg) {
+             @SuppressWarnings("unchecked")
+             AbstractList<String> requestedDownloads = (AbstractList<String>) msg.obj;
+             if (msg.obj != null) {
+                 Iterator<String> it = requestedDownloads.iterator();
+                 while (it.hasNext()) {
+                     mService.downloadFile(it.next());
+                 }
+             }
+             mService.stopSelf(msg.arg1);
+         }
+     }
+     
 -    
+     /**
+      * Core download method: requests a file to download and stores it.
+      * 
+      * @param downloadKey   Key to access the download to perform, contained in mPendingDownloads 
+      */
+     private void downloadFile(String downloadKey) {
+         
+         synchronized(mPendingDownloads) {
+             mCurrentDownload = mPendingDownloads.get(downloadKey);
+         }
+         
+         if (mCurrentDownload != null) {
+             
+             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);
+                 }
+             }
+             
+             /// notify result
+             notifyDownloadResult(mCurrentDownload, downloadResult);
+             
+             sendBroadcastDownloadFinished(mCurrentDownload, downloadResult);
+         }
+     }
+     /**
+      * Updates the OC File after a successful download.
+      */
+     private void saveDownloadedFile() {
+         OCFile file = mCurrentDownload.getFile();
+         long syncDate = System.currentTimeMillis();
+         file.setLastSyncDateForProperties(syncDate);
+         file.setLastSyncDateForData(syncDate);
+         file.setModificationTimestamp(mCurrentDownload.getModificationTimestamp());
+         file.setModificationTimestampAtLastSyncForData(mCurrentDownload.getModificationTimestamp());
+         // file.setEtag(mCurrentDownload.getEtag());    // TODO Etag, where available
+         file.setMimetype(mCurrentDownload.getMimeType());
+         file.setStoragePath(mCurrentDownload.getSavePath());
+         file.setFileLength((new File(mCurrentDownload.getSavePath()).length()));
+         mStorageManager.saveFile(file);
+     }
+     /**
+      * Creates a status notification to show the download progress
+      * 
+      * @param download  Download operation starting.
+      */
+     private void notifyDownloadStart(DownloadFileOperation download) {
+         /// create status notification with a progress bar
+         mLastPercent = 0;
+         mNotification = new Notification(R.drawable.icon, getString(R.string.downloader_download_in_progress_ticker), System.currentTimeMillis());
+         mNotification.flags |= Notification.FLAG_ONGOING_EVENT;
+         mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbar_layout);
+         mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, download.getSize() < 0);
+         mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.downloader_download_in_progress_content), 0, new File(download.getSavePath()).getName()));
+         mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon);
+         
+         /// includes a pending intent in the notification showing the details view of the file
+         Intent showDetailsIntent = null;
+         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);
+         mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0);
+         
+         mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification);
+     }
+     
+     /**
+      * Callback method to update the progress bar in the status notification.
+      */
+     @Override
+     public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileName) {
+         int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));
+         if (percent != mLastPercent) {
+           mNotification.contentView.setProgressBar(R.id.status_progress, 100, percent, totalToTransfer < 0);
+           String text = String.format(getString(R.string.downloader_download_in_progress_content), percent, fileName);
+           mNotification.contentView.setTextViewText(R.id.status_text, text);
+           mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification);
+         }
+         mLastPercent = percent;
+     }
+     
+     
+     /**
+      * Callback method to update the progress bar in the status notification (old version)
+      */
+     @Override
+     public void onTransferProgress(long progressRate) {
+         // NOTHING TO DO HERE ANYMORE
+     }
+     
+     /**
+      * Updates the status notification with the result of a download operation.
+      * 
+      * @param downloadResult    Result of the download operation.
+      * @param download          Finished download operation
+      */
+     private void notifyDownloadResult(DownloadFileOperation download, RemoteOperationResult downloadResult) {
+         mNotificationManager.cancel(R.string.downloader_download_in_progress_ticker);
+         if (!downloadResult.isCancelled()) {
+             int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker : R.string.downloader_download_failed_ticker;
+             int contentId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_content : R.string.downloader_download_failed_content;
+             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);
+         }
+     }
+     
+     
+     /**
+      * Sends a broadcast when a download finishes in order to the interested activities can update their view
+      * 
+      * @param download          Finished download operation
+      * @param downloadResult    Result of the download operation
+      */
+     private void sendBroadcastDownloadFinished(DownloadFileOperation download, RemoteOperationResult downloadResult) {
+         Intent end = new Intent(DOWNLOAD_FINISH_MESSAGE);
+         end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess());
+         end.putExtra(ACCOUNT_NAME, download.getAccount().name);
+         end.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());
+         end.putExtra(EXTRA_FILE_PATH, download.getSavePath());
+         sendStickyBroadcast(end);
+     }
+     
+     
+     /**
+      * Sends a broadcast when a new download is added to the queue.
+      * 
+      * @param download          Added download operation
+      */
+     private void sendBroadcastNewDownload(DownloadFileOperation download) {
+         Intent added = new Intent(DOWNLOAD_ADDED_MESSAGE);
+         added.putExtra(ACCOUNT_NAME, download.getAccount().name);
+         added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());
+         added.putExtra(EXTRA_FILE_PATH, download.getSavePath());
+         sendStickyBroadcast(added);
+     }
+ }
@@@ -40,7 -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 {
  
  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;
+ import java.util.Map;
  import java.util.Vector;
  import java.util.concurrent.ConcurrentHashMap;
  import java.util.concurrent.ConcurrentMap;
@@@ -31,30 -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.files.InstantUploadBroadcastReceiver;
 +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;
@@@ -67,12 -45,34 +67,19 @@@ import android.os.IBinder
  import android.os.Looper;
  import android.os.Message;
  import android.os.Process;
- import android.util.Log;
  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 {
  
       */
      public void uploadFile(String uploadKey) {
  
-         synchronized(mPendingUploads) {
+         synchronized (mPendingUploads) {
              mCurrentUpload = mPendingUploads.get(uploadKey);
          }
-         
          if (mCurrentUpload != null) {
-             
              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 {
-                     RemoteOperation operation = new CreateFolderOperation(  InstantUploadBroadcastReceiver.INSTANT_UPLOAD_DIR, 
 +                /// 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.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
++                Log_OC.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
 +                uploadResult = new RemoteOperationResult(e);
 +                
 +            } catch (IOException e) {
-                 Log.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
++                Log_OC.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
 +                uploadResult = new RemoteOperationResult(e);
 +                
              } finally {
-                 synchronized(mPendingUploads) {
+                 synchronized (mPendingUploads) {
                      mPendingUploads.remove(uploadKey);
+                     Log_OC.i(TAG, "Remove CurrentUploadItem from pending upload Item Map.");
                  }
              }
 -
 -            // notify result
 +            
 +            /// notify result
-             notifyUploadResult(uploadResult, mCurrentUpload);
 +            
+             notifyUploadResult(uploadResult, mCurrentUpload);
              sendFinalBroadcast(mCurrentUpload, uploadResult);
-             
          }
-         
      }
  
      /**
              showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, upload.getFile());
              showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, upload.getAccount());
              showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-             mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0);
-             
-             mNotification.setLatestEventInfo(   getApplicationContext(), 
-                                                 getString(R.string.uploader_upload_succeeded_ticker), 
-                                                 String.format(getString(R.string.uploader_upload_succeeded_content_single), upload.getFileName()), 
-                                                 mNotification.contentIntent);
-             
-             mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotification);    // NOT AN ERROR; uploader_upload_in_progress_ticker is the target, not a new notification
-             
-             /* Notification about multiple uploads: pending of update
-             mNotification.setLatestEventInfo(   getApplicationContext(), 
-                                                     getString(R.string.uploader_upload_succeeded_ticker), 
-                                                     String.format(getString(R.string.uploader_upload_succeeded_content_multiple), mSuccessCounter), 
-                                                     mNotification.contentIntent);
-              */
-             
+             mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(),
+                     (int) System.currentTimeMillis(), showDetailsIntent, 0);
+             mNotification.setLatestEventInfo(getApplicationContext(),
+                     getString(R.string.uploader_upload_succeeded_ticker),
+                     String.format(getString(R.string.uploader_upload_succeeded_content_single), upload.getFileName()),
+                     mNotification.contentIntent);
+             mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotification); // NOT
+                                                                                                      // AN
+             DbHandler db = new DbHandler(this.getBaseContext());
+             db.removeIUPendingFile(mCurrentUpload.getFile().getStoragePath());
+             db.close();
          } else {
-             /// fail -> explicit failure notification
+             // / fail -> explicit failure notification
              mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker);
-             Notification finalNotification = new Notification(R.drawable.icon, getString(R.string.uploader_upload_failed_ticker), System.currentTimeMillis());
+             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) {
-                 // TODO we need a class to provide error messages for the users from a RemoteOperationResult and a RemoteOperation 
-                 content = String.format(getString(R.string.error__upload__local_file_not_copied), upload.getFileName(), getString(R.string.app_name));
+             String content = null;
+             if (uploadResult.getCode() == ResultCode.LOCAL_STORAGE_FULL
+                     || uploadResult.getCode() == ResultCode.LOCAL_STORAGE_NOT_COPIED) {
+                 // TODO we need a class to provide error messages for the users
+                 // from a RemoteOperationResult and a RemoteOperation
+                 content = String.format(getString(R.string.error__upload__local_file_not_copied), upload.getFileName(),
+                         getString(R.string.app_name));
+             } else if (uploadResult.getCode() == ResultCode.QUOTA_EXCEEDED) {
+                 content = getString(R.string.failed_upload_quota_exceeded_text);
              } else {
-                 content = String.format(getString(R.string.uploader_upload_failed_content_single), upload.getFileName());
+                 content = String
+                         .format(getString(R.string.uploader_upload_failed_content_single), upload.getFileName());
              }
-             finalNotification.setLatestEventInfo(   getApplicationContext(), 
-                                                     getString(R.string.uploader_upload_failed_ticker), 
-                                                     content, 
-                                                     finalNotification.contentIntent);
-             
+             // we add only for instant-uploads the InstantUploadActivity and the
+             // db entry
+             Intent detailUploadIntent = null;
+             if (upload.isInstant() && InstantUploadActivity.IS_ENABLED) {
+                 detailUploadIntent = new Intent(this, InstantUploadActivity.class);
+                 detailUploadIntent.putExtra(FileUploader.KEY_ACCOUNT, upload.getAccount());
+             } else {
+                 detailUploadIntent = new Intent(this, FailedUploadActivity.class);
+                 detailUploadIntent.putExtra(FailedUploadActivity.MESSAGE, content);
+             }
+             finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(),
+                     (int) System.currentTimeMillis(), detailUploadIntent, PendingIntent.FLAG_UPDATE_CURRENT
+                             | PendingIntent.FLAG_ONE_SHOT);
+             if (upload.isInstant()) {
+                 DbHandler db = null;
+                 try {
+                     db = new DbHandler(this.getBaseContext());
+                     String message = uploadResult.getLogMessage() + " errorCode: " + uploadResult.getCode();
+                     Log_OC.e(TAG, message + " Http-Code: " + uploadResult.getHttpCode());
+                     if (uploadResult.getCode() == ResultCode.QUOTA_EXCEEDED) {
+                         message = getString(R.string.failed_upload_quota_exceeded_text);
+                     }
+                     if (db.updateFileState(upload.getOriginalStoragePath(), DbHandler.UPLOAD_STATUS_UPLOAD_FAILED,
+                             message) == 0) {
+                         db.putFileForLater(upload.getOriginalStoragePath(), upload.getAccount().name, message);
+                     }
+                 } finally {
+                     if (db != null) {
+                         db.close();
+                     }
+                 }
+             }
+             finalNotification.setLatestEventInfo(getApplicationContext(),
+                     getString(R.string.uploader_upload_failed_ticker), content, finalNotification.contentIntent);
              mNotificationManager.notify(R.string.uploader_upload_failed_ticker, finalNotification);
-             
-             /* Notification about multiple uploads failure: pending of update
-             finalNotification.setLatestEventInfo(   getApplicationContext(), 
-                                                         getString(R.string.uploader_upload_failed_ticker), 
-                                                         String.format(getString(R.string.uploader_upload_failed_content_multiple), mSuccessCounter, mTotalFilesToSend), 
-                                                         finalNotification.contentIntent);
-             } */                
          }
-         
      }
-     
-     
      /**
-      * Sends a broadcast in order to the interested activities can update their view
+      * Sends a broadcast in order to the interested activities can update their
+      * view
       * 
-      * @param upload          Finished upload operation
-      * @param uploadResult    Result of the upload operation
+      * @param upload Finished upload operation
+      * @param uploadResult Result of the upload operation
       */
      private void sendFinalBroadcast(UploadFileOperation upload, RemoteOperationResult uploadResult) {
          Intent end = new Intent(UPLOAD_FINISH_MESSAGE);
@@@ -25,7 -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 {
  
@@@ -28,9 -27,10 +27,9 @@@ 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;
  import com.owncloud.android.R;
  
  public class LocationUpdateService extends IntentService implements
@@@ -40,8 -39,10 +39,8 @@@ import org.apache.commons.httpclient.pa
  import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
  import org.apache.http.conn.ssl.X509HostnameVerifier;
  
- import android.util.Log;
+ 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.
@@@ -32,8 -31,10 +31,8 @@@ import javax.net.ssl.TrustManager
  import javax.net.ssl.TrustManagerFactory;
  import javax.net.ssl.X509TrustManager;
  
- import android.util.Log;
+ import com.owncloud.android.Log_OC;
  
 -import android.util.Log;
 -
  /**
   * @author David A. Velasco
   */
index 7739822,0000000..a426734
mode 100644,000000..100644
--- /dev/null
@@@ -1,269 -1,0 +1,268 @@@
-  *   it under the terms of the GNU General Public License as published by
-  *   the Free Software Foundation, either version 3 of the License, or
-  *   (at your option) any later version.
 +/* ownCloud Android client application
 + *   Copyright (C) 2012  ownCloud Inc.
 + *
 + *   This program is free software: you can redistribute it and/or modify
- import android.util.Log;
++ *   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;
 +
-         Log.d(TAG, "enter BearerScheme.authenticate(Credentials, String, String)");
++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.d(TAG, "enter BearerScheme.authenticate(Credentials, HttpMethod)");
++        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.d(TAG, "enter BearerAuthScheme.authenticate(BearerCredentials, String)");
++        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");
 +    }
 +    
 +}
index 59596e8,0000000..50799b0
mode 100644,000000..100644
--- /dev/null
@@@ -1,98 -1,0 +1,97 @@@
-  *   it under the terms of the GNU General Public License as published by
-  *   the Free Software Foundation, either version 3 of the License, or
-  *   (at your option) any later version.
 +/* 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;
 +    }
 +
 +}
 +
@@@ -38,20 -37,15 +37,20 @@@ import org.apache.http.conn.ssl.Browser
  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;
- import android.util.Log;
  
  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.d(TAG, "Creating WebdavClient associated to " + account.name);
++        //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;
      }
          
          return client;
      }
      
 -    
      /**
       * Creates a WebdavClient to access a URL and sets the desired parameters for ownCloud client connections.
       * 
       * @return          A WebdavClient object ready to be used
       */
      public static WebdavClient createOwnCloudClient(Uri uri, Context context) {
-         //Log.d(TAG, "Creating WebdavClient for " + uri);
 -        Log_OC.d(TAG, "Creating WebdavClient for " + uri);
++        //Log_OC.d(TAG, "Creating WebdavClient for " + uri);
          
          //allowSelfsignedCertificates(true);
          try {
@@@ -28,10 -27,12 +27,11 @@@ import java.util.Random
  import org.apache.commons.httpclient.HttpException;
  import org.apache.commons.httpclient.methods.PutMethod;
  
+ import com.owncloud.android.Log_OC;
  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;
index 4d42478,0000000..5965db3
mode 100644,000000..100644
--- /dev/null
@@@ -1,96 -1,0 +1,94 @@@
-  *   it under the terms of the GNU General Public License as published by
-  *   the Free Software Foundation, either version 3 of the License, or
-  *   (at your option) any later version.
 +/* ownCloud Android client application
 + *   Copyright (C) 2012 ownCloud Inc.
 + *
 + *   This program is free software: you can redistribute it and/or modify
- import android.util.Log;
++ *   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;
 +
-             Log.d(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage());
 +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.e(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage(), e);
++            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;
 +    }
 +    
 +}
@@@ -42,7 -42,7 +42,6 @@@ import eu.alefzero.webdav.OnDatatransfe
  import eu.alefzero.webdav.WebdavClient;
  import eu.alefzero.webdav.WebdavUtils;
  import android.accounts.Account;
--import android.util.Log;
  import android.webkit.MimeTypeMap;
  
  /**
index d678ac3,0000000..1093986
mode 100644,000000..100644
--- /dev/null
@@@ -1,94 -1,0 +1,94 @@@
-  *   it under the terms of the GNU General Public License as published by
-  *   the Free Software Foundation, either version 3 of the License, or
-  *   (at your option) any later version.
 +/* ownCloud Android client application
 + *   Copyright (C) 2012 ownCloud Inc.
 + *
 + *   This program is free software: you can redistribute it and/or modify
- import android.util.Log;
++ *   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;
-             Log.d(TAG, "Existence check for " + client.getBaseUri() + mPath + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + "finished with HTTP status " + status + (!success?"(FAIL)":""));
 +
 +/**
 + * 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.e(TAG, "Existence check for " + client.getBaseUri() + mPath + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + ": " + result.getLogMessage(), result.getException());
++            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();
 +    }
 +
 +
 +}
index b64ebce,0000000..6d43caf
mode 100644,000000..100644
--- /dev/null
@@@ -1,175 -1,0 +1,174 @@@
- import android.util.Log;
 +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;
 +
-                 Log.i(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage());
 +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.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage(), result.getException());
++                Log_OC.i(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage());
 +            
 +            } else if (result.getException() != null) {
-                     Log.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + ((mResultTokenMap != null) ? mResultTokenMap.get(OAuth2Constants.KEY_ERROR) : "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.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage());
++                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.v(TAG, "[" + i + "," + j + "] = " + p);
++                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));
 +        }
 +    }
 +
 +}
index 7132c53,0000000..1afcf6e
mode 100644,000000..100644
--- /dev/null
@@@ -1,138 -1,0 +1,137 @@@
-  *   it under the terms of the GNU General Public License as published by
-  *   the Free Software Foundation, either version 2 of the License, or
-  *   (at your option) any later version.
 +/* ownCloud Android client application
 + *   Copyright (C) 2012-2013 ownCloud Inc.
 + *
 + *   This program is free software: you can redistribute it and/or modify
- import android.util.Log;
++ *   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.GetMethod;
 +import org.json.JSONException;
 +import org.json.JSONObject;
 +
 +import com.owncloud.android.AccountUtils;
++import com.owncloud.android.Log_OC;
 +import com.owncloud.android.utils.OwnCloudVersion;
 +
 +import eu.alefzero.webdav.WebdavClient;
 +import android.content.Context;
 +import android.net.ConnectivityManager;
 +import android.net.Uri;
-             Log.i(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage());
 +
 +public class OwnCloudServerCheckOperation extends RemoteOperation {
 +    
 +    /** Maximum time to wait for a response from the server when the connection is being tested, in MILLISECONDs.  */
 +    public static final int TRY_CONNECTION_TIMEOUT = 5000;
 +    
 +    private static final String TAG = OwnCloudServerCheckOperation.class.getSimpleName();
 +    
 +    private String mUrl;
 +    private RemoteOperationResult mLatestResult;
 +    private Context mContext;
 +    private OwnCloudVersion mOCVersion;
 +
 +    public OwnCloudServerCheckOperation(String url, Context context) {
 +        mUrl = url;
 +        mContext = context;
 +        mOCVersion = null;
 +    }
 +    
 +    public OwnCloudVersion getDiscoveredVersion() {
 +        return mOCVersion;
 +    }
 +
 +    private boolean tryConnection(WebdavClient wc, String urlSt) {
 +        boolean retval = false;
 +        GetMethod get = null;
 +        try {
 +            get = new GetMethod(urlSt);
 +            int status = wc.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT);
 +            String response = get.getResponseBodyAsString();
 +            if (status == HttpStatus.SC_OK) {
 +                JSONObject json = new JSONObject(response);
 +                if (!json.getBoolean("installed")) {
 +                    mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
 +                } else {
 +                    mOCVersion = new OwnCloudVersion(json.getString("version"));
 +                    if (!mOCVersion.isVersionValid()) {
 +                        mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.BAD_OC_VERSION);
 +                        
 +                    } else {
 +                        mLatestResult = new RemoteOperationResult(urlSt.startsWith("https://") ? 
 +                                                                    RemoteOperationResult.ResultCode.OK_SSL : 
 +                                                                    RemoteOperationResult.ResultCode.OK_NO_SSL
 +                            );
 +
 +                        retval = true;
 +                    }
 +                }
 +                
 +            } else {
 +                mLatestResult = new RemoteOperationResult(false, status);
 +            }
 +
 +        } catch (JSONException e) {
 +            mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
 +            
 +        } catch (Exception e) {
 +            mLatestResult = new RemoteOperationResult(e);
 +            
 +        } finally {
 +            if (get != null)
 +                get.releaseConnection();
 +        }
 +        
 +        if (mLatestResult.isSuccess()) {
-             Log.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage(), mLatestResult.getException());
++            Log_OC.i(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage());
 +            
 +        } else if (mLatestResult.getException() != null) {
-             Log.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage());
++            Log_OC.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage(), mLatestResult.getException());
 +            
 +        } else {
-                 Log.d(TAG, "establishing secure connection failed, trying non secure connection");
++            Log_OC.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage());
 +        }
 +
 +        return retval;
 +    }
 +
 +    private boolean isOnline() {
 +        ConnectivityManager cm = (ConnectivityManager) mContext
 +                .getSystemService(Context.CONNECTIVITY_SERVICE);
 +        return cm != null && cm.getActiveNetworkInfo() != null
 +                && cm.getActiveNetworkInfo().isConnectedOrConnecting();
 +    }
 +
 +      @Override
 +      protected RemoteOperationResult run(WebdavClient client) {
 +        if (!isOnline()) {
 +              return new RemoteOperationResult(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION);
 +        }
 +        if (mUrl.startsWith("http://") || mUrl.startsWith("https://")) {
 +            tryConnection(client, mUrl + AccountUtils.STATUS_PATH);
 +            
 +        } else {
 +            client.setBaseUri(Uri.parse("https://" + mUrl + AccountUtils.STATUS_PATH));
 +            boolean httpsSuccess = tryConnection(client, "https://" + mUrl + AccountUtils.STATUS_PATH); 
 +            if (!httpsSuccess && !mLatestResult.isSslRecoverableException()) {
++                Log_OC.d(TAG, "establishing secure connection failed, trying non secure connection");
 +                client.setBaseUri(Uri.parse("http://" + mUrl + AccountUtils.STATUS_PATH));
 +                tryConnection(client, "http://" + mUrl + AccountUtils.STATUS_PATH);
 +            }
 +        }
 +        return mLatestResult;
 +      }
 +      
 +}
   */
  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 android.util.Log;
  
  import eu.alefzero.webdav.WebdavClient;
  
@@@ -71,34 -44,6 +70,34 @@@ public abstract class RemoteOperation i
         */
        protected abstract RemoteOperationResult run(WebdavClient client); 
        
-             Log.e(TAG, "Error while trying to access to " + mAccount.name, e);
 +
 +    /**
 +     * 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
         */
      @Override
      public final void run() {
 -      final RemoteOperationResult result = execute(mClient);
 +        RemoteOperationResult result = null;
 +        boolean repeat = false;
 +        do {
 +            try{
 +                if (mClient == null) {
 +                    if (mAccount != null && mContext != null) {
 +                        if (mCallerActivity != null) {
 +                            mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext, mCallerActivity);
 +                        } else {
 +                            mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext);
 +                        }
 +                    } else {
 +                        throw new IllegalStateException("Trying to run a remote operation asynchronously with no client instance or account");
 +                    }
 +                }
 +            
 +            } catch (IOException e) {
-                 Log.e(TAG, "Error while trying to access to " + mAccount.name, new AccountsException("I/O exception while trying to authorize the account", e));
++                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.e(TAG, "Error while trying to access to " + mAccount.name, 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
@@@ -33,9 -32,11 +32,9 @@@ import org.apache.commons.httpclient.Ht
  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;
  
  /**
   * The result of a remote operation required to an ownCloud server.
   * 
   * @author David A. Velasco
   */
  public class RemoteOperationResult implements Serializable {
-     
      /** Generated - should be refreshed every time the class changes!! */
      private static final long serialVersionUID = -7805531062432602444L;
 -
 -    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
 +    
+     private static final String TAG = "RemoteOperationResult";
-         OAUTH2_ERROR_ACCESS_DENIED
++    
 +    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;
@@@ -21,8 -20,9 +20,7 @@@ 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;
  
@@@ -25,8 -24,9 +24,8 @@@ import org.apache.jackrabbit.webdav.cli
  //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;
  import com.owncloud.android.datamodel.OCFile;
  import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
@@@ -26,8 -25,9 +25,8 @@@ import org.apache.jackrabbit.webdav.cli
  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;
  import com.owncloud.android.datamodel.OCFile;
  import com.owncloud.android.files.services.FileDownloader;
@@@ -35,8 -34,9 +34,8 @@@ import org.apache.jackrabbit.webdav.cli
  
  import android.accounts.Account;
  import android.content.Context;
--import android.util.Log;
  
+ import com.owncloud.android.Log_OC;
  import com.owncloud.android.datamodel.DataStorageManager;
  import com.owncloud.android.datamodel.OCFile;
  import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
@@@ -26,10 -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.authenticator.AccountAuthenticator;
 +import com.owncloud.android.authentication.AccountAuthenticator;
+ import com.owncloud.android.Log_OC;
  import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
  import com.owncloud.android.utils.OwnCloudVersion;
  
- /* ownCloud Android client application\r
-  *   Copyright (C) 2011  Bartek Przybylski\r
-  *   Copyright (C) 2012-2013 ownCloud Inc.\r
-  *\r
-  *   This program is free software: you can redistribute it and/or modify\r
-  *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 2 of the License, or\r
-  *   (at your option) any later version.\r
-  *\r
-  *   This program is distributed in the hope that it will be useful,\r
-  *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-  *   GNU General Public License for more details.\r
-  *\r
-  *   You should have received a copy of the GNU General Public License\r
-  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
-  *\r
-  */\r
\r
- package com.owncloud.android.providers;\r
\r
- import java.util.HashMap;\r
\r
- import com.owncloud.android.db.ProviderMeta;\r
- import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;\r
\r
\r
- import android.content.ContentProvider;\r
- import android.content.ContentUris;\r
- import android.content.ContentValues;\r
- import android.content.Context;\r
- import android.content.UriMatcher;\r
- import android.database.Cursor;\r
- import android.database.SQLException;\r
- import android.database.sqlite.SQLiteDatabase;\r
- import android.database.sqlite.SQLiteOpenHelper;\r
- import android.database.sqlite.SQLiteQueryBuilder;\r
- import android.net.Uri;\r
- import android.text.TextUtils;\r
- import android.util.Log;\r
\r
- /**\r
-  * The ContentProvider for the ownCloud App.\r
-  * \r
-  * @author Bartek Przybylski\r
-  * \r
-  */\r
- public class FileContentProvider extends ContentProvider {\r
\r
-     private DataBaseHelper mDbHelper;\r
\r
-     private static HashMap<String, String> mProjectionMap;\r
-     static {\r
-         mProjectionMap = new HashMap<String, String>();\r
-         mProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID);\r
-         mProjectionMap.put(ProviderTableMeta.FILE_PARENT,\r
-                 ProviderTableMeta.FILE_PARENT);\r
-         mProjectionMap.put(ProviderTableMeta.FILE_PATH,\r
-                 ProviderTableMeta.FILE_PATH);\r
-         mProjectionMap.put(ProviderTableMeta.FILE_NAME,\r
-                 ProviderTableMeta.FILE_NAME);\r
-         mProjectionMap.put(ProviderTableMeta.FILE_CREATION,\r
-                 ProviderTableMeta.FILE_CREATION);\r
-         mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED,\r
-                 ProviderTableMeta.FILE_MODIFIED);\r
-         mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,\r
-                 ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA);\r
-         mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH,\r
-                 ProviderTableMeta.FILE_CONTENT_LENGTH);\r
-         mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE,\r
-                 ProviderTableMeta.FILE_CONTENT_TYPE);\r
-         mProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH,\r
-                 ProviderTableMeta.FILE_STORAGE_PATH);\r
-         mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE,\r
-                 ProviderTableMeta.FILE_LAST_SYNC_DATE);\r
-         mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA,\r
-                 ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA);\r
-         mProjectionMap.put(ProviderTableMeta.FILE_KEEP_IN_SYNC,\r
-                 ProviderTableMeta.FILE_KEEP_IN_SYNC);\r
-         mProjectionMap.put(ProviderTableMeta.FILE_ACCOUNT_OWNER,\r
-                 ProviderTableMeta.FILE_ACCOUNT_OWNER);\r
-     }\r
\r
-     private static final int SINGLE_FILE = 1;\r
-     private static final int DIRECTORY = 2;\r
-     private static final int ROOT_DIRECTORY = 3;\r
-     private static final UriMatcher mUriMatcher;\r
-     static {\r
-         mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);\r
-         mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "/", ROOT_DIRECTORY);\r
-         mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE);\r
-         mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE);\r
-         mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY);\r
-     }\r
\r
-     @Override\r
-     public int delete(Uri uri, String where, String[] whereArgs) {\r
-         SQLiteDatabase db = mDbHelper.getWritableDatabase();\r
-         int count = 0;\r
-         switch (mUriMatcher.match(uri)) {\r
-         case SINGLE_FILE:\r
-             count = db.delete(ProviderTableMeta.DB_NAME,\r
-                     ProviderTableMeta._ID\r
-                             + "="\r
-                             + uri.getPathSegments().get(1)\r
-                             + (!TextUtils.isEmpty(where) ? " AND (" + where\r
-                                     + ")" : ""), whereArgs);\r
-             break;\r
-         case ROOT_DIRECTORY:\r
-             count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs);\r
-             break;\r
-         default:\r
-             throw new IllegalArgumentException("Unknown uri: " + uri.toString());\r
-         }\r
-         getContext().getContentResolver().notifyChange(uri, null);\r
-         return count;\r
-     }\r
\r
-     @Override\r
-     public String getType(Uri uri) {\r
-         switch (mUriMatcher.match(uri)) {\r
-         case ROOT_DIRECTORY:\r
-             return ProviderTableMeta.CONTENT_TYPE;\r
-         case SINGLE_FILE:\r
-             return ProviderTableMeta.CONTENT_TYPE_ITEM;\r
-         default:\r
-             throw new IllegalArgumentException("Unknown Uri id."\r
-                     + uri.toString());\r
-         }\r
-     }\r
\r
-     @Override\r
-     public Uri insert(Uri uri, ContentValues values) {\r
-         if (mUriMatcher.match(uri) != SINGLE_FILE &&\r
-             mUriMatcher.match(uri) != ROOT_DIRECTORY) {\r
-             \r
-             throw new IllegalArgumentException("Unknown uri id: " + uri);\r
-         }\r
\r
-         SQLiteDatabase db = mDbHelper.getWritableDatabase();\r
-         long rowId = db.insert(ProviderTableMeta.DB_NAME, null, values);\r
-         if (rowId > 0) {\r
-             Uri insertedFileUri = ContentUris.withAppendedId(\r
-                     ProviderTableMeta.CONTENT_URI_FILE, rowId);\r
-             getContext().getContentResolver().notifyChange(insertedFileUri,\r
-                     null);\r
-             return insertedFileUri;\r
-         }\r
-         throw new SQLException("ERROR " + uri);\r
-     }\r
\r
-     @Override\r
-     public boolean onCreate() {\r
-         mDbHelper = new DataBaseHelper(getContext());\r
-         return true;\r
-     }\r
\r
-     @Override\r
-     public Cursor query(Uri uri, String[] projection, String selection,\r
-             String[] selectionArgs, String sortOrder) {\r
-         SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder();\r
\r
-         sqlQuery.setTables(ProviderTableMeta.DB_NAME);\r
-         sqlQuery.setProjectionMap(mProjectionMap);\r
\r
-         switch (mUriMatcher.match(uri)) {\r
-         case ROOT_DIRECTORY:\r
-             break;\r
-         case DIRECTORY:\r
-             sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="\r
-                     + uri.getPathSegments().get(1));\r
-             break;\r
-         case SINGLE_FILE:\r
-             if (uri.getPathSegments().size() > 1) {\r
-                 sqlQuery.appendWhere(ProviderTableMeta._ID + "="\r
-                         + uri.getPathSegments().get(1));\r
-             }\r
-             break;\r
-         default:\r
-             throw new IllegalArgumentException("Unknown uri id: " + uri);\r
-         }\r
\r
-         String order;\r
-         if (TextUtils.isEmpty(sortOrder)) {\r
-             order = ProviderTableMeta.DEFAULT_SORT_ORDER;\r
-         } else {\r
-             order = sortOrder;\r
-         }\r
\r
-         SQLiteDatabase db = mDbHelper.getReadableDatabase();\r
-         Cursor c = sqlQuery.query(db, projection, selection, selectionArgs,\r
-                 null, null, order);\r
\r
-         c.setNotificationUri(getContext().getContentResolver(), uri);\r
\r
-         return c;\r
-     }\r
\r
-     @Override\r
-     public int update(Uri uri, ContentValues values, String selection,\r
-             String[] selectionArgs) {\r
-         return mDbHelper.getWritableDatabase().update(\r
-                 ProviderTableMeta.DB_NAME, values, selection, selectionArgs);\r
-     }\r
\r
-     class DataBaseHelper extends SQLiteOpenHelper {\r
\r
-         public DataBaseHelper(Context context) {\r
-             super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION);\r
\r
-         }\r
\r
-         @Override\r
-         public void onCreate(SQLiteDatabase db) {\r
-             // files table\r
-             Log.i("SQL", "Entering in onCreate");\r
-             db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "("\r
-                     + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "\r
-                     + ProviderTableMeta.FILE_NAME + " TEXT, "\r
-                     + ProviderTableMeta.FILE_PATH + " TEXT, "\r
-                     + ProviderTableMeta.FILE_PARENT + " INTEGER, "\r
-                     + ProviderTableMeta.FILE_CREATION + " INTEGER, "\r
-                     + ProviderTableMeta.FILE_MODIFIED + " INTEGER, "\r
-                     + ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, "\r
-                     + ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, "\r
-                     + ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, "\r
-                     + ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT, "\r
-                     + ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, "\r
-                     + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER, "\r
-                     + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, "\r
-                     + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER );"\r
-                     );\r
-         }\r
\r
-         @Override\r
-         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\r
-             Log.i("SQL", "Entering in onUpgrade");\r
-             boolean upgraded = false; \r
-             if (oldVersion == 1 && newVersion >= 2) {\r
-                 Log.i("SQL", "Entering in the #1 ADD in onUpgrade");\r
-                 db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +\r
-                            " ADD COLUMN " + ProviderTableMeta.FILE_KEEP_IN_SYNC  + " INTEGER " +\r
-                            " DEFAULT 0");\r
-                 upgraded = true;\r
-             }\r
-             if (oldVersion < 3 && newVersion >= 3) {\r
-                 Log.i("SQL", "Entering in the #2 ADD in onUpgrade");\r
-                 db.beginTransaction();\r
-                 try {\r
-                     db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +\r
-                                " ADD COLUMN " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA  + " INTEGER " +\r
-                                " DEFAULT 0");\r
-                     \r
-                     // assume there are not local changes pending to upload\r
-                     db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + \r
-                             " SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = " + System.currentTimeMillis() + \r
-                             " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");\r
-                  \r
-                     upgraded = true;\r
-                     db.setTransactionSuccessful();\r
-                 } finally {\r
-                     db.endTransaction();\r
-                 }\r
-             }\r
-             if (oldVersion < 4 && newVersion >= 4) {\r
-                 Log.i("SQL", "Entering in the #3 ADD in onUpgrade");\r
-                 db.beginTransaction();\r
-                 try {\r
-                     db .execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +\r
-                            " ADD COLUMN " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA  + " INTEGER " +\r
-                            " DEFAULT 0");\r
-                 \r
-                     db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + \r
-                            " SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " + ProviderTableMeta.FILE_MODIFIED + \r
-                            " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");\r
-                 \r
-                     upgraded = true;\r
-                     db.setTransactionSuccessful();\r
-                 } finally {\r
-                     db.endTransaction();\r
-                 }\r
-             }\r
-             if (!upgraded)\r
-                 Log.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);\r
-         }\r
\r
-     }\r
\r
- }\r
+ /* ownCloud Android client application
+  *   Copyright (C) 2011  Bartek Przybylski
+  *   Copyright (C) 2012-2013 ownCloud Inc.
+  *
+  *   This program is free software: you can redistribute it and/or modify
+  *   it under the terms of the GNU General Public License 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.providers;
+ import java.util.HashMap;
+ import com.owncloud.android.Log_OC;
+ import com.owncloud.android.db.ProviderMeta;
+ import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
+ import android.content.ContentProvider;
+ import android.content.ContentUris;
+ import android.content.ContentValues;
+ import android.content.Context;
+ import android.content.UriMatcher;
+ import android.database.Cursor;
+ import android.database.SQLException;
+ import android.database.sqlite.SQLiteDatabase;
+ 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.
+  * 
+  * @author Bartek Przybylski
+  * 
+  */
+ public class FileContentProvider extends ContentProvider {
+     private DataBaseHelper mDbHelper;
+     private static HashMap<String, String> mProjectionMap;
+     static {
+         mProjectionMap = new HashMap<String, String>();
+         mProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID);
+         mProjectionMap.put(ProviderTableMeta.FILE_PARENT,
+                 ProviderTableMeta.FILE_PARENT);
+         mProjectionMap.put(ProviderTableMeta.FILE_PATH,
+                 ProviderTableMeta.FILE_PATH);
+         mProjectionMap.put(ProviderTableMeta.FILE_NAME,
+                 ProviderTableMeta.FILE_NAME);
+         mProjectionMap.put(ProviderTableMeta.FILE_CREATION,
+                 ProviderTableMeta.FILE_CREATION);
+         mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED,
+                 ProviderTableMeta.FILE_MODIFIED);
+         mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
+                 ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA);
+         mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH,
+                 ProviderTableMeta.FILE_CONTENT_LENGTH);
+         mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE,
+                 ProviderTableMeta.FILE_CONTENT_TYPE);
+         mProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH,
+                 ProviderTableMeta.FILE_STORAGE_PATH);
+         mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE,
+                 ProviderTableMeta.FILE_LAST_SYNC_DATE);
+         mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA,
+                 ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA);
+         mProjectionMap.put(ProviderTableMeta.FILE_KEEP_IN_SYNC,
+                 ProviderTableMeta.FILE_KEEP_IN_SYNC);
+         mProjectionMap.put(ProviderTableMeta.FILE_ACCOUNT_OWNER,
+                 ProviderTableMeta.FILE_ACCOUNT_OWNER);
+     }
+     private static final int SINGLE_FILE = 1;
+     private static final int DIRECTORY = 2;
+     private static final int ROOT_DIRECTORY = 3;
+     private static final UriMatcher mUriMatcher;
+     static {
+         mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+         mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "/", ROOT_DIRECTORY);
+         mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE);
+         mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE);
+         mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY);
+     }
+     @Override
+     public int delete(Uri uri, String where, String[] whereArgs) {
+         SQLiteDatabase db = mDbHelper.getWritableDatabase();
+         int count = 0;
+         switch (mUriMatcher.match(uri)) {
+         case SINGLE_FILE:
+             count = db.delete(ProviderTableMeta.DB_NAME,
+                     ProviderTableMeta._ID
+                             + "="
+                             + uri.getPathSegments().get(1)
+                             + (!TextUtils.isEmpty(where) ? " AND (" + where
+                                     + ")" : ""), whereArgs);
+             break;
+         case ROOT_DIRECTORY:
+             count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs);
+             break;
+         default:
+             throw new IllegalArgumentException("Unknown uri: " + uri.toString());
+         }
+         getContext().getContentResolver().notifyChange(uri, null);
+         return count;
+     }
+     @Override
+     public String getType(Uri uri) {
+         switch (mUriMatcher.match(uri)) {
+         case ROOT_DIRECTORY:
+             return ProviderTableMeta.CONTENT_TYPE;
+         case SINGLE_FILE:
+             return ProviderTableMeta.CONTENT_TYPE_ITEM;
+         default:
+             throw new IllegalArgumentException("Unknown Uri id."
+                     + uri.toString());
+         }
+     }
+     @Override
+     public Uri insert(Uri uri, ContentValues values) {
+         if (mUriMatcher.match(uri) != SINGLE_FILE &&
+             mUriMatcher.match(uri) != ROOT_DIRECTORY) {
+             
+             throw new IllegalArgumentException("Unknown uri id: " + uri);
+         }
+         SQLiteDatabase db = mDbHelper.getWritableDatabase();
+         long rowId = db.insert(ProviderTableMeta.DB_NAME, null, values);
+         if (rowId > 0) {
+             Uri insertedFileUri = ContentUris.withAppendedId(
+                     ProviderTableMeta.CONTENT_URI_FILE, rowId);
+             getContext().getContentResolver().notifyChange(insertedFileUri,
+                     null);
+             return insertedFileUri;
+         }
+         throw new SQLException("ERROR " + uri);
+     }
+     @Override
+     public boolean onCreate() {
+         mDbHelper = new DataBaseHelper(getContext());
+         return true;
+     }
+     @Override
+     public Cursor query(Uri uri, String[] projection, String selection,
+             String[] selectionArgs, String sortOrder) {
+         SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder();
+         sqlQuery.setTables(ProviderTableMeta.DB_NAME);
+         sqlQuery.setProjectionMap(mProjectionMap);
+         switch (mUriMatcher.match(uri)) {
+         case ROOT_DIRECTORY:
+             break;
+         case DIRECTORY:
+             sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="
+                     + uri.getPathSegments().get(1));
+             break;
+         case SINGLE_FILE:
+             if (uri.getPathSegments().size() > 1) {
+                 sqlQuery.appendWhere(ProviderTableMeta._ID + "="
+                         + uri.getPathSegments().get(1));
+             }
+             break;
+         default:
+             throw new IllegalArgumentException("Unknown uri id: " + uri);
+         }
+         String order;
+         if (TextUtils.isEmpty(sortOrder)) {
+             order = ProviderTableMeta.DEFAULT_SORT_ORDER;
+         } else {
+             order = sortOrder;
+         }
+         SQLiteDatabase db = mDbHelper.getReadableDatabase();
+         Cursor c = sqlQuery.query(db, projection, selection, selectionArgs,
+                 null, null, order);
+         c.setNotificationUri(getContext().getContentResolver(), uri);
+         return c;
+     }
+     @Override
+     public int update(Uri uri, ContentValues values, String selection,
+             String[] selectionArgs) {
+         return mDbHelper.getWritableDatabase().update(
+                 ProviderTableMeta.DB_NAME, values, selection, selectionArgs);
+     }
+     class DataBaseHelper extends SQLiteOpenHelper {
+         public DataBaseHelper(Context context) {
+             super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION);
+         }
+         @Override
+         public void onCreate(SQLiteDatabase db) {
+             // files table
+             Log_OC.i("SQL", "Entering in onCreate");
+             db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "("
+                     + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
+                     + ProviderTableMeta.FILE_NAME + " TEXT, "
+                     + ProviderTableMeta.FILE_PATH + " TEXT, "
+                     + ProviderTableMeta.FILE_PARENT + " INTEGER, "
+                     + ProviderTableMeta.FILE_CREATION + " INTEGER, "
+                     + ProviderTableMeta.FILE_MODIFIED + " INTEGER, "
+                     + ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, "
+                     + ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, "
+                     + ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, "
+                     + ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT, "
+                     + ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, "
+                     + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER, "
+                     + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, "
+                     + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER );"
+                     );
+         }
+         @Override
+         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+             Log_OC.i("SQL", "Entering in onUpgrade");
+             boolean upgraded = false; 
+             if (oldVersion == 1 && newVersion >= 2) {
+                 Log_OC.i("SQL", "Entering in the #1 ADD in onUpgrade");
+                 db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +
+                            " ADD COLUMN " + ProviderTableMeta.FILE_KEEP_IN_SYNC  + " INTEGER " +
+                            " DEFAULT 0");
+                 upgraded = true;
+             }
+             if (oldVersion < 3 && newVersion >= 3) {
+                 Log_OC.i("SQL", "Entering in the #2 ADD in onUpgrade");
+                 db.beginTransaction();
+                 try {
+                     db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +
+                                " ADD COLUMN " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA  + " INTEGER " +
+                                " DEFAULT 0");
+                     
+                     // assume there are not local changes pending to upload
+                     db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + 
+                             " SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = " + System.currentTimeMillis() + 
+                             " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");
+                  
+                     upgraded = true;
+                     db.setTransactionSuccessful();
+                 } finally {
+                     db.endTransaction();
+                 }
+             }
+             if (oldVersion < 4 && newVersion >= 4) {
+                 Log_OC.i("SQL", "Entering in the #3 ADD in onUpgrade");
+                 db.beginTransaction();
+                 try {
+                     db .execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +
+                            " ADD COLUMN " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA  + " INTEGER " +
+                            " DEFAULT 0");
+                 
+                     db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + 
+                            " SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " + ProviderTableMeta.FILE_MODIFIED + 
+                            " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");
+                 
+                     upgraded = true;
+                     db.setTransactionSuccessful();
+                 } finally {
+                     db.endTransaction();
+                 }
+             }
+             if (!upgraded)
+                 Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);
+         }
+     }
+ }
- /* ownCloud Android client application\r
-  *   Copyright (C) 2011  Bartek Przybylski\r
-  *   Copyright (C) 2012-2013 ownCloud Inc.\r
-  *\r
-  *   This program is free software: you can redistribute it and/or modify\r
-  *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 2 of the License, or\r
-  *   (at your option) any later version.\r
-  *\r
-  *   This program is distributed in the hope that it will be useful,\r
-  *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-  *   GNU General Public License for more details.\r
-  *\r
-  *   You should have received a copy of the GNU General Public License\r
-  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
-  *\r
-  */\r
\r
- package com.owncloud.android.syncadapter;\r
\r
- import java.io.IOException;\r
- import java.util.ArrayList;\r
- import java.util.HashMap;\r
- import java.util.List;\r
- import java.util.Map;\r
\r
- import org.apache.jackrabbit.webdav.DavException;\r
\r
- import com.owncloud.android.R;\r
- import com.owncloud.android.authentication.AuthenticatorActivity;\r
- import com.owncloud.android.datamodel.DataStorageManager;\r
- import com.owncloud.android.datamodel.FileDataStorageManager;\r
- import com.owncloud.android.datamodel.OCFile;\r
- import com.owncloud.android.operations.RemoteOperationResult;\r
- import com.owncloud.android.operations.SynchronizeFolderOperation;\r
- import com.owncloud.android.operations.UpdateOCVersionOperation;\r
- import com.owncloud.android.operations.RemoteOperationResult.ResultCode;\r
- import com.owncloud.android.ui.activity.ErrorsWhileCopyingHandlerActivity;\r
\r
- import android.accounts.Account;\r
- import android.accounts.AccountsException;\r
- import android.app.Notification;\r
- import android.app.NotificationManager;\r
- import android.app.PendingIntent;\r
- import android.content.ContentProviderClient;\r
- import android.content.ContentResolver;\r
- import android.content.Context;\r
- import android.content.Intent;\r
- import android.content.SyncResult;\r
- import android.os.Bundle;\r
- import android.util.Log;\r
\r
- /**\r
-  * SyncAdapter implementation for syncing sample SyncAdapter contacts to the\r
-  * platform ContactOperations provider.\r
-  * \r
-  * @author Bartek Przybylski\r
-  */\r
- public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {\r
\r
-     private final static String TAG = "FileSyncAdapter";\r
\r
-     /** \r
-      * Maximum number of failed folder synchronizations that are supported before finishing the synchronization operation\r
-      */\r
-     private static final int MAX_FAILED_RESULTS = 3; \r
-     \r
-     private long mCurrentSyncTime;\r
-     private boolean mCancellation;\r
-     private boolean mIsManualSync;\r
-     private int mFailedResultsCounter;    \r
-     private RemoteOperationResult mLastFailedResult;\r
-     private SyncResult mSyncResult;\r
-     private int mConflictsFound;\r
-     private int mFailsInFavouritesFound;\r
-     private Map<String, String> mForgottenLocalFiles;\r
\r
-     \r
-     public FileSyncAdapter(Context context, boolean autoInitialize) {\r
-         super(context, autoInitialize);\r
-     }\r
\r
-     /**\r
-      * {@inheritDoc}\r
-      */\r
-     @Override\r
-     public synchronized void onPerformSync(Account account, Bundle extras,\r
-             String authority, ContentProviderClient provider,\r
-             SyncResult syncResult) {\r
\r
-         mCancellation = false;\r
-         mIsManualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);\r
-         mFailedResultsCounter = 0;\r
-         mLastFailedResult = null;\r
-         mConflictsFound = 0;\r
-         mFailsInFavouritesFound = 0;\r
-         mForgottenLocalFiles = new HashMap<String, String>();\r
-         mSyncResult = syncResult;\r
-         mSyncResult.fullSyncRequested = false;\r
-         mSyncResult.delayUntil = 60*60*24; // sync after 24h\r
\r
-         this.setAccount(account);\r
-         this.setContentProvider(provider);\r
-         this.setStorageManager(new FileDataStorageManager(account, getContentProvider()));\r
-         try {\r
-             this.initClientForCurrentAccount();\r
-         } catch (IOException e) {\r
-             /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again\r
-             mSyncResult.tooManyRetries = true;\r
-             notifyFailedSynchronization();\r
-             return;\r
-         } catch (AccountsException e) {\r
-             /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again\r
-             mSyncResult.tooManyRetries = true;\r
-             notifyFailedSynchronization();\r
-             return;\r
-         }\r
-         \r
-         Log.d(TAG, "Synchronization of ownCloud account " + account.name + " starting");\r
-         sendStickyBroadcast(true, null, null);  // message to signal the start of the synchronization to the UI\r
-         \r
-         try {\r
-             updateOCVersion();\r
-             mCurrentSyncTime = System.currentTimeMillis();\r
-             if (!mCancellation) {\r
-                 fetchData(OCFile.PATH_SEPARATOR, DataStorageManager.ROOT_PARENT_ID);\r
-                 \r
-             } else {\r
-                 Log.d(TAG, "Leaving synchronization before any remote request due to cancellation was requested");\r
-             }\r
-             \r
-             \r
-         } finally {\r
-             // it's important making this although very unexpected errors occur; that's the reason for the finally\r
-             \r
-             if (mFailedResultsCounter > 0 && mIsManualSync) {\r
-                 /// don't let the system synchronization manager retries MANUAL synchronizations\r
-                 //      (be careful: "MANUAL" currently includes the synchronization requested when a new account is created and when the user changes the current account)\r
-                 mSyncResult.tooManyRetries = true;\r
-                 \r
-                 /// notify the user about the failure of MANUAL synchronization\r
-                 notifyFailedSynchronization();\r
-                 \r
-             }\r
-             if (mConflictsFound > 0 || mFailsInFavouritesFound > 0) {\r
-                 notifyFailsInFavourites();\r
-             }\r
-             if (mForgottenLocalFiles.size() > 0) {\r
-                 notifyForgottenLocalFiles();\r
-                 \r
-             }\r
-             sendStickyBroadcast(false, null, mLastFailedResult);        // message to signal the end to the UI\r
-         }\r
-         \r
-     }\r
\r
-     \r
-     /**\r
-      * Called by system SyncManager when a synchronization is required to be cancelled.\r
-      * \r
-      * Sets the mCancellation flag to 'true'. THe synchronization will be stopped when before a new folder is fetched. Data of the last folder\r
-      * fetched will be still saved in the database. See onPerformSync implementation.\r
-      */\r
-     @Override\r
-     public void onSyncCanceled() {\r
-         Log.d(TAG, "Synchronization of " + getAccount().name + " has been requested to cancel");\r
-         mCancellation = true;\r
-         super.onSyncCanceled();\r
-     }\r
-     \r
-     \r
-     /**\r
-      * Updates the locally stored version value of the ownCloud server\r
-      */\r
-     private void updateOCVersion() {\r
-         UpdateOCVersionOperation update = new UpdateOCVersionOperation(getAccount(), getContext());\r
-         RemoteOperationResult result = update.execute(getClient());\r
-         if (!result.isSuccess()) {\r
-             mLastFailedResult = result; \r
-         }\r
-     }\r
\r
-     \r
-     \r
-     /**\r
-      * Synchronize the properties of files and folders contained in a remote folder given by remotePath.\r
-      * \r
-      * @param remotePath        Remote path to the folder to synchronize.\r
-      * @param parentId          Database Id of the folder to synchronize.\r
-      */\r
-     private void fetchData(String remotePath, long parentId) {\r
-         \r
-         if (mFailedResultsCounter > MAX_FAILED_RESULTS || isFinisher(mLastFailedResult))\r
-             return;\r
-         \r
-         // perform folder synchronization\r
-         SynchronizeFolderOperation synchFolderOp = new SynchronizeFolderOperation(  remotePath, \r
-                                                                                     mCurrentSyncTime, \r
-                                                                                     parentId, \r
-                                                                                     getStorageManager(), \r
-                                                                                     getAccount(), \r
-                                                                                     getContext()\r
-                                                                                   );\r
-         RemoteOperationResult result = synchFolderOp.execute(getClient());\r
-         \r
-         \r
-         // synchronized folder -> notice to UI - ALWAYS, although !result.isSuccess\r
-         sendStickyBroadcast(true, remotePath, null);\r
-         \r
-         if (result.isSuccess() || result.getCode() == ResultCode.SYNC_CONFLICT) {\r
-             \r
-             if (result.getCode() == ResultCode.SYNC_CONFLICT) {\r
-                 mConflictsFound += synchFolderOp.getConflictsFound();\r
-                 mFailsInFavouritesFound += synchFolderOp.getFailsInFavouritesFound();\r
-             }\r
-             if (synchFolderOp.getForgottenLocalFiles().size() > 0) {\r
-                 mForgottenLocalFiles.putAll(synchFolderOp.getForgottenLocalFiles());\r
-             }\r
-             // synchronize children folders \r
-             List<OCFile> children = synchFolderOp.getChildren();\r
-             fetchChildren(children);    // beware of the 'hidden' recursion here!\r
-             \r
-         } else {\r
-             if (result.getCode() == RemoteOperationResult.ResultCode.UNAUTHORIZED) {\r
-                 mSyncResult.stats.numAuthExceptions++;\r
-                 \r
-             } else if (result.getException() instanceof DavException) {\r
-                 mSyncResult.stats.numParseExceptions++;\r
-                 \r
-             } else if (result.getException() instanceof IOException) { \r
-                 mSyncResult.stats.numIoExceptions++;\r
-             }\r
-             mFailedResultsCounter++;\r
-             mLastFailedResult = result;\r
-         }\r
-             \r
-     }\r
\r
-     /**\r
-      * Checks if a failed result should terminate the synchronization process immediately, according to\r
-      * OUR OWN POLICY\r
-      * \r
-      * @param   failedResult        Remote operation result to check.\r
-      * @return                      'True' if the result should immediately finish the synchronization\r
-      */\r
-     private boolean isFinisher(RemoteOperationResult failedResult) {\r
-         if  (failedResult != null) {\r
-             RemoteOperationResult.ResultCode code = failedResult.getCode();\r
-             return (code.equals(RemoteOperationResult.ResultCode.SSL_ERROR) ||\r
-                     code.equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) ||\r
-                     code.equals(RemoteOperationResult.ResultCode.UNAUTHORIZED) ||\r
-                     code.equals(RemoteOperationResult.ResultCode.BAD_OC_VERSION) ||\r
-                     code.equals(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED));\r
-         }\r
-         return false;\r
-     }\r
\r
-     /**\r
-      * Synchronize data of folders in the list of received files\r
-      * \r
-      * @param files         Files to recursively fetch \r
-      */\r
-     private void fetchChildren(List<OCFile> files) {\r
-         int i;\r
-         for (i=0; i < files.size() && !mCancellation; i++) {\r
-             OCFile newFile = files.get(i);\r
-             if (newFile.isDirectory()) {\r
-                 fetchData(newFile.getRemotePath(), newFile.getFileId());\r
-             }\r
-         }\r
-         if (mCancellation && i <files.size()) Log.d(TAG, "Leaving synchronization before synchronizing " + files.get(i).getRemotePath() + " because cancelation request");\r
-     }\r
\r
-     \r
-     /**\r
-      * Sends a message to any application component interested in the progress of the synchronization.\r
-      * \r
-      * @param inProgress        'True' when the synchronization progress is not finished.\r
-      * @param dirRemotePath     Remote path of a folder that was just synchronized (with or without success)\r
-      */\r
-     private void sendStickyBroadcast(boolean inProgress, String dirRemotePath, RemoteOperationResult result) {\r
-         Intent i = new Intent(FileSyncService.SYNC_MESSAGE);\r
-         i.putExtra(FileSyncService.IN_PROGRESS, inProgress);\r
-         i.putExtra(FileSyncService.ACCOUNT_NAME, getAccount().name);\r
-         if (dirRemotePath != null) {\r
-             i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath);\r
-         }\r
-         if (result != null) {\r
-             i.putExtra(FileSyncService.SYNC_RESULT, result);\r
-         }\r
-         getContext().sendStickyBroadcast(i);\r
-     }\r
\r
-     \r
-     \r
-     /**\r
-      * Notifies the user about a failed synchronization through the status notification bar \r
-      */\r
-     private void notifyFailedSynchronization() {\r
-         Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_ticker), System.currentTimeMillis());\r
-         notification.flags |= Notification.FLAG_AUTO_CANCEL;\r
-         boolean needsToUpdateCredentials = (mLastFailedResult != null && mLastFailedResult.getCode() == ResultCode.UNAUTHORIZED);\r
-         // TODO put something smart in the contentIntent below for all the possible errors\r
-         notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);\r
-         if (needsToUpdateCredentials) {\r
-             // let the user update credentials with one click\r
-             Intent updateAccountCredentials = new Intent(getContext(), AuthenticatorActivity.class);\r
-             updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, getAccount());\r
-             updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);\r
-             updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\r
-             updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);\r
-             updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);\r
-             notification.contentIntent = PendingIntent.getActivity(getContext(), (int)System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT);\r
-             notification.setLatestEventInfo(getContext().getApplicationContext(), \r
-                     getContext().getString(R.string.sync_fail_ticker), \r
-                     String.format(getContext().getString(R.string.sync_fail_content_unauthorized), getAccount().name), \r
-                     notification.contentIntent);\r
-         } else {\r
-             notification.setLatestEventInfo(getContext().getApplicationContext(), \r
-                     getContext().getString(R.string.sync_fail_ticker), \r
-                     String.format(getContext().getString(R.string.sync_fail_content), getAccount().name), \r
-                     notification.contentIntent);\r
-         }\r
-         ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_ticker, notification);\r
-     }\r
\r
\r
-     /**\r
-      * Notifies the user about conflicts and strange fails when trying to synchronize the contents of kept-in-sync files.\r
-      * \r
-      * By now, we won't consider a failed synchronization.\r
-      */\r
-     private void notifyFailsInFavourites() {\r
-         if (mFailedResultsCounter > 0) {\r
-             Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_in_favourites_ticker), System.currentTimeMillis());\r
-             notification.flags |= Notification.FLAG_AUTO_CANCEL;\r
-             // TODO put something smart in the contentIntent below\r
-             notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);\r
-             notification.setLatestEventInfo(getContext().getApplicationContext(), \r
-                                             getContext().getString(R.string.sync_fail_in_favourites_ticker), \r
-                                             String.format(getContext().getString(R.string.sync_fail_in_favourites_content), mFailedResultsCounter + mConflictsFound, mConflictsFound), \r
-                                             notification.contentIntent);\r
-             ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_in_favourites_ticker, notification);\r
-             \r
-         } else {\r
-             Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_conflicts_in_favourites_ticker), System.currentTimeMillis());\r
-             notification.flags |= Notification.FLAG_AUTO_CANCEL;\r
-             // TODO put something smart in the contentIntent below\r
-             notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);\r
-             notification.setLatestEventInfo(getContext().getApplicationContext(), \r
-                                             getContext().getString(R.string.sync_conflicts_in_favourites_ticker), \r
-                                             String.format(getContext().getString(R.string.sync_conflicts_in_favourites_content), mConflictsFound), \r
-                                             notification.contentIntent);\r
-             ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_conflicts_in_favourites_ticker, notification);\r
-         } \r
-     }\r
\r
-     \r
-     /**\r
-      * Notifies the user about local copies of files out of the ownCloud local directory that were 'forgotten' because \r
-      * copying them inside the ownCloud local directory was not possible.\r
-      * \r
-      * We don't want links to files out of the ownCloud local directory (foreign files) anymore. It's easy to have \r
-      * synchronization problems if a local file is linked to more than one remote file.\r
-      * \r
-      * We won't consider a synchronization as failed when foreign files can not be copied to the ownCloud local directory.\r
-      */\r
-     private void notifyForgottenLocalFiles() {\r
-         Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_foreign_files_forgotten_ticker), System.currentTimeMillis());\r
-         notification.flags |= Notification.FLAG_AUTO_CANCEL;\r
\r
-         /// includes a pending intent in the notification showing a more detailed explanation\r
-         Intent explanationIntent = new Intent(getContext(), ErrorsWhileCopyingHandlerActivity.class);\r
-         explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_ACCOUNT, getAccount());\r
-         ArrayList<String> remotePaths = new ArrayList<String>();\r
-         ArrayList<String> localPaths = new ArrayList<String>();\r
-         remotePaths.addAll(mForgottenLocalFiles.keySet());\r
-         localPaths.addAll(mForgottenLocalFiles.values());\r
-         explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_LOCAL_PATHS, localPaths);\r
-         explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_REMOTE_PATHS, remotePaths);  \r
-         explanationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
-         \r
-         notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), explanationIntent, 0);\r
-         notification.setLatestEventInfo(getContext().getApplicationContext(), \r
-                                         getContext().getString(R.string.sync_foreign_files_forgotten_ticker), \r
-                                         String.format(getContext().getString(R.string.sync_foreign_files_forgotten_content), mForgottenLocalFiles.size(), getContext().getString(R.string.app_name)), \r
-                                         notification.contentIntent);\r
-         ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_foreign_files_forgotten_ticker, notification);\r
-         \r
-     }\r
-     \r
-     \r
- }\r
+ /* ownCloud Android client application
+  *   Copyright (C) 2011  Bartek Przybylski
+  *   Copyright (C) 2012-2013 ownCloud Inc.
+  *
+  *   This program is free software: you can redistribute it and/or modify
+  *   it under the terms of the GNU General Public License 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.syncadapter;
+ import java.io.IOException;
 -import java.net.UnknownHostException;
+ import java.util.ArrayList;
+ import java.util.HashMap;
+ import java.util.List;
+ import java.util.Map;
+ 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;
+ import com.owncloud.android.operations.RemoteOperationResult;
+ import com.owncloud.android.operations.SynchronizeFolderOperation;
+ 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;
+ import android.content.ContentProviderClient;
+ import android.content.ContentResolver;
+ 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 {
+     private final static String TAG = "FileSyncAdapter";
+     /** 
+      * Maximum number of failed folder synchronizations that are supported before finishing the synchronization operation
+      */
+     private static final int MAX_FAILED_RESULTS = 3; 
+     
+     private long mCurrentSyncTime;
+     private boolean mCancellation;
+     private boolean mIsManualSync;
+     private int mFailedResultsCounter;    
+     private RemoteOperationResult mLastFailedResult;
+     private SyncResult mSyncResult;
+     private int mConflictsFound;
+     private int mFailsInFavouritesFound;
+     private Map<String, String> mForgottenLocalFiles;
+     
+     public FileSyncAdapter(Context context, boolean autoInitialize) {
+         super(context, autoInitialize);
+     }
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public synchronized void onPerformSync(Account account, Bundle extras,
+             String authority, ContentProviderClient provider,
+             SyncResult syncResult) {
+         mCancellation = false;
+         mIsManualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
+         mFailedResultsCounter = 0;
+         mLastFailedResult = null;
+         mConflictsFound = 0;
+         mFailsInFavouritesFound = 0;
+         mForgottenLocalFiles = new HashMap<String, String>();
+         mSyncResult = syncResult;
+         mSyncResult.fullSyncRequested = false;
+         mSyncResult.delayUntil = 60*60*24; // sync after 24h
+         this.setAccount(account);
+         this.setContentProvider(provider);
+         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;
+         }
+         
+         Log_OC.d(TAG, "Synchronization of ownCloud account " + account.name + " starting");
+         sendStickyBroadcast(true, null, null);  // message to signal the start of the synchronization to the UI
+         
+         try {
+             updateOCVersion();
+             mCurrentSyncTime = System.currentTimeMillis();
+             if (!mCancellation) {
+                 fetchData(OCFile.PATH_SEPARATOR, DataStorageManager.ROOT_PARENT_ID);
+                 
+             } else {
+                 Log_OC.d(TAG, "Leaving synchronization before any remote request due to cancellation was requested");
+             }
+             
+             
+         } finally {
+             // it's important making this although very unexpected errors occur; that's the reason for the finally
+             
+             if (mFailedResultsCounter > 0 && mIsManualSync) {
+                 /// don't let the system synchronization manager retries MANUAL synchronizations
+                 //      (be careful: "MANUAL" currently includes the synchronization requested when a new account is created and when the user changes the current account)
+                 mSyncResult.tooManyRetries = true;
+                 
+                 /// notify the user about the failure of MANUAL synchronization
+                 notifyFailedSynchronization();
+                 
+             }
+             if (mConflictsFound > 0 || mFailsInFavouritesFound > 0) {
+                 notifyFailsInFavourites();
+             }
+             if (mForgottenLocalFiles.size() > 0) {
+                 notifyForgottenLocalFiles();
+                 
+             }
+             sendStickyBroadcast(false, null, mLastFailedResult);        // message to signal the end to the UI
+         }
+         
+     }
 -
+     
+     /**
+      * Called by system SyncManager when a synchronization is required to be cancelled.
+      * 
+      * Sets the mCancellation flag to 'true'. THe synchronization will be stopped when before a new folder is fetched. Data of the last folder
+      * fetched will be still saved in the database. See onPerformSync implementation.
+      */
+     @Override
+     public void onSyncCanceled() {
+         Log_OC.d(TAG, "Synchronization of " + getAccount().name + " has been requested to cancel");
+         mCancellation = true;
+         super.onSyncCanceled();
+     }
+     
+     
+     /**
+      * Updates the locally stored version value of the ownCloud server
+      */
+     private void updateOCVersion() {
+         UpdateOCVersionOperation update = new UpdateOCVersionOperation(getAccount(), getContext());
+         RemoteOperationResult result = update.execute(getClient());
+         if (!result.isSuccess()) {
+             mLastFailedResult = result; 
+         }
+     }
 -
+     
+     
+     /**
+      * Synchronize the properties of files and folders contained in a remote folder given by remotePath.
+      * 
+      * @param remotePath        Remote path to the folder to synchronize.
+      * @param parentId          Database Id of the folder to synchronize.
+      */
+     private void fetchData(String remotePath, long parentId) {
+         
+         if (mFailedResultsCounter > MAX_FAILED_RESULTS || isFinisher(mLastFailedResult))
+             return;
+         
+         // perform folder synchronization
+         SynchronizeFolderOperation synchFolderOp = new SynchronizeFolderOperation(  remotePath, 
+                                                                                     mCurrentSyncTime, 
+                                                                                     parentId, 
+                                                                                     getStorageManager(), 
+                                                                                     getAccount(), 
+                                                                                     getContext()
+                                                                                   );
+         RemoteOperationResult result = synchFolderOp.execute(getClient());
+         
+         
+         // synchronized folder -> notice to UI - ALWAYS, although !result.isSuccess
+         sendStickyBroadcast(true, remotePath, null);
+         
+         if (result.isSuccess() || result.getCode() == ResultCode.SYNC_CONFLICT) {
+             
+             if (result.getCode() == ResultCode.SYNC_CONFLICT) {
+                 mConflictsFound += synchFolderOp.getConflictsFound();
+                 mFailsInFavouritesFound += synchFolderOp.getFailsInFavouritesFound();
+             }
+             if (synchFolderOp.getForgottenLocalFiles().size() > 0) {
+                 mForgottenLocalFiles.putAll(synchFolderOp.getForgottenLocalFiles());
+             }
+             // synchronize children folders 
+             List<OCFile> children = synchFolderOp.getChildren();
+             fetchChildren(children);    // beware of the 'hidden' recursion here!
+             
+         } else {
+             if (result.getCode() == RemoteOperationResult.ResultCode.UNAUTHORIZED) {
+                 mSyncResult.stats.numAuthExceptions++;
+                 
+             } else if (result.getException() instanceof DavException) {
+                 mSyncResult.stats.numParseExceptions++;
+                 
+             } else if (result.getException() instanceof IOException) { 
+                 mSyncResult.stats.numIoExceptions++;
+             }
+             mFailedResultsCounter++;
+             mLastFailedResult = result;
+         }
+             
+     }
+     /**
+      * Checks if a failed result should terminate the synchronization process immediately, according to
+      * OUR OWN POLICY
+      * 
+      * @param   failedResult        Remote operation result to check.
+      * @return                      'True' if the result should immediately finish the synchronization
+      */
+     private boolean isFinisher(RemoteOperationResult failedResult) {
+         if  (failedResult != null) {
+             RemoteOperationResult.ResultCode code = failedResult.getCode();
+             return (code.equals(RemoteOperationResult.ResultCode.SSL_ERROR) ||
+                     code.equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) ||
+                     code.equals(RemoteOperationResult.ResultCode.BAD_OC_VERSION) ||
+                     code.equals(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED));
+         }
+         return false;
+     }
+     /**
+      * Synchronize data of folders in the list of received files
+      * 
+      * @param files         Files to recursively fetch 
+      */
+     private void fetchChildren(List<OCFile> files) {
+         int i;
+         for (i=0; i < files.size() && !mCancellation; i++) {
+             OCFile newFile = files.get(i);
+             if (newFile.isDirectory()) {
+                 fetchData(newFile.getRemotePath(), newFile.getFileId());
+             }
+         }
+         if (mCancellation && i <files.size()) Log_OC.d(TAG, "Leaving synchronization before synchronizing " + files.get(i).getRemotePath() + " because cancelation request");
+     }
+     
+     /**
+      * Sends a message to any application component interested in the progress of the synchronization.
+      * 
+      * @param inProgress        'True' when the synchronization progress is not finished.
+      * @param dirRemotePath     Remote path of a folder that was just synchronized (with or without success)
+      */
+     private void sendStickyBroadcast(boolean inProgress, String dirRemotePath, RemoteOperationResult result) {
+         Intent i = new Intent(FileSyncService.SYNC_MESSAGE);
+         i.putExtra(FileSyncService.IN_PROGRESS, inProgress);
+         i.putExtra(FileSyncService.ACCOUNT_NAME, getAccount().name);
+         if (dirRemotePath != null) {
+             i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath);
+         }
+         if (result != null) {
+             i.putExtra(FileSyncService.SYNC_RESULT, result);
+         }
+         getContext().sendStickyBroadcast(i);
+     }
+     
+     
+     /**
+      * Notifies the user about a failed synchronization through the status notification bar 
+      */
+     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);
+     }
+     /**
+      * Notifies the user about conflicts and strange fails when trying to synchronize the contents of kept-in-sync files.
+      * 
+      * By now, we won't consider a failed synchronization.
+      */
+     private void notifyFailsInFavourites() {
+         if (mFailedResultsCounter > 0) {
+             Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_in_favourites_ticker), System.currentTimeMillis());
+             notification.flags |= Notification.FLAG_AUTO_CANCEL;
+             // TODO put something smart in the contentIntent below
+             notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);
+             notification.setLatestEventInfo(getContext().getApplicationContext(), 
+                                             getContext().getString(R.string.sync_fail_in_favourites_ticker), 
+                                             String.format(getContext().getString(R.string.sync_fail_in_favourites_content), mFailedResultsCounter + mConflictsFound, mConflictsFound), 
+                                             notification.contentIntent);
+             ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_in_favourites_ticker, notification);
+             
+         } else {
+             Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_conflicts_in_favourites_ticker), System.currentTimeMillis());
+             notification.flags |= Notification.FLAG_AUTO_CANCEL;
+             // TODO put something smart in the contentIntent below
+             notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);
+             notification.setLatestEventInfo(getContext().getApplicationContext(), 
+                                             getContext().getString(R.string.sync_conflicts_in_favourites_ticker), 
+                                             String.format(getContext().getString(R.string.sync_conflicts_in_favourites_content), mConflictsFound), 
+                                             notification.contentIntent);
+             ((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 
+      * copying them inside the ownCloud local directory was not possible.
+      * 
+      * We don't want links to files out of the ownCloud local directory (foreign files) anymore. It's easy to have 
+      * synchronization problems if a local file is linked to more than one remote file.
+      * 
+      * We won't consider a synchronization as failed when foreign files can not be copied to the ownCloud local directory.
+      */
+     private void notifyForgottenLocalFiles() {
+         Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_foreign_files_forgotten_ticker), System.currentTimeMillis());
+         notification.flags |= Notification.FLAG_AUTO_CANCEL;
+         /// includes a pending intent in the notification showing a more detailed explanation
+         Intent explanationIntent = new Intent(getContext(), ErrorsWhileCopyingHandlerActivity.class);
+         explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_ACCOUNT, getAccount());
+         ArrayList<String> remotePaths = new ArrayList<String>();
+         ArrayList<String> localPaths = new ArrayList<String>();
+         remotePaths.addAll(mForgottenLocalFiles.keySet());
+         localPaths.addAll(mForgottenLocalFiles.values());
+         explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_LOCAL_PATHS, localPaths);
+         explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_REMOTE_PATHS, remotePaths);  
+         explanationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+         
+         notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), explanationIntent, 0);
+         notification.setLatestEventInfo(getContext().getApplicationContext(), 
+                                         getContext().getString(R.string.sync_foreign_files_forgotten_ticker), 
+                                         String.format(getContext().getString(R.string.sync_foreign_files_forgotten_content), mForgottenLocalFiles.size(), getContext().getString(R.string.app_name)), 
+                                         notification.contentIntent);
+         ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_foreign_files_forgotten_ticker, notification);
+         
+     }
+     
+     
+ }
@@@ -33,7 -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;
@@@ -50,7 -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.authenticator.AccountAuthenticator;
 +import com.owncloud.android.authentication.AccountAuthenticator;
+ import com.owncloud.android.Log_OC;
  
  import com.owncloud.android.R;
  
@@@ -29,7 -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;
index 0000000,e468ffb..4c13fb2
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,49 +1,55 @@@
 - * \r
++/* ownCloud Android client application\r
++ *   Copyright (C) 2012-2013 ownCloud Inc.\r
++ *\r
++ *   This program is free software: you can redistribute it and/or modify\r
++ *   it under the terms of the GNU General Public License version 2,\r
++ *   as published by the Free Software Foundation.\r
++ *\r
++ *   This program is distributed in the hope that it will be useful,\r
++ *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
++ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
++ *   GNU General Public License for more details.\r
++ *\r
++ *   You should have received a copy of the GNU General Public License\r
++ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
++ *\r
++ */\r
++\r
+ package com.owncloud.android.ui.activity;\r
\r
+ import android.app.Activity;\r
+ import android.os.Bundle;\r
+ import android.view.View;\r
+ import android.view.View.OnClickListener;\r
+ import android.widget.Button;\r
+ import android.widget.TextView;\r
\r
+ import com.owncloud.android.R;\r
\r
+ /**\r
+  * This Activity is used to display a detail message for failed uploads\r
+  * \r
+  * The entry-point for this activity is the 'Failed upload Notification"\r
+  * \r
 - * \r
 - *         This program is free software: you can redistribute it and/or modify\r
 - *         it under the terms of the GNU General Public License as published by\r
 - *         the Free Software Foundation, either version 3 of the License. (at\r
 - *         your option) any later version.\r
 - * \r
 - *         This program is distributed in the hope that it will be useful, but\r
 - *         WITHOUT ANY WARRANTY; without even the implied warranty of\r
 - *         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
 - *         General Public License for more de/\r
+  * @author andomaex / Matthias Baumann\r
+  */\r
+ public class FailedUploadActivity extends Activity {\r
\r
+     public static final String MESSAGE = "message";\r
\r
+     @Override\r
+     public void onCreate(Bundle savedInstanceState) {\r
+         super.onCreate(savedInstanceState);\r
+         setContentView(R.layout.failed_upload_message_view);\r
+         String message = getIntent().getStringExtra(MESSAGE);\r
+         TextView textView = (TextView) findViewById(R.id.faild_upload_message);\r
+         textView.setText(message);\r
+         Button close_button = (Button) findViewById(R.id.failed_uploadactivity_close_button);\r
+         close_button.setOnClickListener(new OnClickListener() {\r
+             @Override\r
+             public void onClick(View v) {\r
+                 finish();\r
+             }\r
+         });\r
+     }\r
+ }\r
- /* ownCloud Android client application\r
-  *   Copyright (C) 2011  Bartek Przybylski\r
-  *   Copyright (C) 2012-2013 ownCloud Inc.\r
-  *\r
-  *   This program is free software: you can redistribute it and/or modify\r
-  *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 2 of the License, or\r
-  *   (at your option) any later version.\r
-  *\r
-  *   This program is distributed in the hope that it will be useful,\r
-  *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-  *   GNU General Public License for more details.\r
-  *\r
-  *   You should have received a copy of the GNU General Public License\r
-  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
-  *\r
-  */\r
- package com.owncloud.android.ui.activity;\r
\r
- import android.accounts.Account;\r
- import android.app.Dialog;\r
- import android.app.ProgressDialog;\r
- import android.content.ComponentName;\r
- import android.content.Context;\r
- import android.content.Intent;\r
- import android.content.ServiceConnection;\r
- import android.content.res.Configuration;\r
- import android.os.Bundle;\r
- import android.os.IBinder;\r
- import android.support.v4.app.FragmentTransaction;\r
- import android.util.Log;\r
\r
- import com.actionbarsherlock.app.ActionBar;\r
- import com.actionbarsherlock.app.SherlockFragmentActivity;\r
- import com.actionbarsherlock.view.MenuItem;\r
- import com.owncloud.android.datamodel.OCFile;\r
- import com.owncloud.android.files.services.FileDownloader;\r
- import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;\r
- import com.owncloud.android.files.services.FileUploader;\r
- import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;\r
- import com.owncloud.android.ui.fragment.FileDetailFragment;\r
\r
- import com.owncloud.android.R;\r
\r
- /**\r
-  * This activity displays the details of a file like its name, its size and so\r
-  * on.\r
-  * \r
-  * @author Bartek Przybylski\r
-  * \r
-  */\r
- public class FileDetailActivity extends SherlockFragmentActivity implements FileDetailFragment.ContainerActivity {\r
-     \r
-     public static final int DIALOG_SHORT_WAIT = 0;\r
\r
-     public static final String TAG = FileDetailActivity.class.getSimpleName();\r
-     \r
-     private boolean mConfigurationChangedToLandscape = false;\r
-     private FileDownloaderBinder mDownloaderBinder = null;\r
-     private ServiceConnection mDownloadConnection, mUploadConnection = null;\r
-     private FileUploaderBinder mUploaderBinder = null;\r
\r
\r
-     @Override\r
-     protected void onCreate(Bundle savedInstanceState) {\r
-         super.onCreate(savedInstanceState);\r
\r
-         // check if configuration changed to large-land ; for a tablet being changed from portrait to landscape when in FileDetailActivity \r
-         Configuration conf = getResources().getConfiguration();\r
-         mConfigurationChangedToLandscape = (conf.orientation == Configuration.ORIENTATION_LANDSCAPE && \r
-                                                 (conf.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE\r
-                                            );\r
\r
-         if (!mConfigurationChangedToLandscape) {\r
-             mDownloadConnection = new DetailsServiceConnection();\r
-             bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);\r
-             mUploadConnection = new DetailsServiceConnection();\r
-             bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);\r
-             \r
-             setContentView(R.layout.file_activity_details);\r
-         \r
-             ActionBar actionBar = getSupportActionBar();\r
-             actionBar.setDisplayHomeAsUpEnabled(true);\r
\r
-             OCFile file = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);\r
-             Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);\r
-             FileDetailFragment mFileDetail = new FileDetailFragment(file, account);\r
-         \r
-             FragmentTransaction ft = getSupportFragmentManager().beginTransaction();\r
-             ft.replace(R.id.fragment, mFileDetail, FileDetailFragment.FTAG);\r
-             ft.commit();\r
-             \r
-         }  else {\r
-             backToDisplayActivity();   // the 'back' won't be effective until this.onStart() and this.onResume() are completed;\r
-         }\r
-         \r
-         \r
-     }\r
-     \r
-     \r
-     /** Defines callbacks for service binding, passed to bindService() */\r
-     private class DetailsServiceConnection implements ServiceConnection {\r
\r
-         @Override\r
-         public void onServiceConnected(ComponentName component, IBinder service) {\r
-             if (component.equals(new ComponentName(FileDetailActivity.this, FileDownloader.class))) {\r
-                 Log.d(TAG, "Download service connected");\r
-                 mDownloaderBinder = (FileDownloaderBinder) service;\r
-             } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) {\r
-                 Log.d(TAG, "Upload service connected");\r
-                 mUploaderBinder = (FileUploaderBinder) service;\r
-             } else {\r
-                 return;\r
-             }\r
-             FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
-             if (fragment != null)\r
-                 fragment.updateFileDetails(false);   // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais())\r
-         }\r
\r
-         @Override\r
-         public void onServiceDisconnected(ComponentName component) {\r
-             if (component.equals(new ComponentName(FileDetailActivity.this, FileDownloader.class))) {\r
-                 Log.d(TAG, "Download service disconnected");\r
-                 mDownloaderBinder = null;\r
-             } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) {\r
-                 Log.d(TAG, "Upload service disconnected");\r
-                 mUploaderBinder = null;\r
-             }\r
-         }\r
-     };    \r
-     \r
\r
-     @Override\r
-     public void onDestroy() {\r
-         super.onDestroy();\r
-         if (mDownloadConnection != null) {\r
-             unbindService(mDownloadConnection);\r
-             mDownloadConnection = null;\r
-         }\r
-         if (mUploadConnection != null) {\r
-             unbindService(mUploadConnection);\r
-             mUploadConnection = null;\r
-         }\r
-     }\r
-     \r
-     \r
-     @Override\r
-     public boolean onOptionsItemSelected(MenuItem item) {\r
-         boolean returnValue = false;\r
-         \r
-         switch(item.getItemId()){\r
-         case android.R.id.home:\r
-             backToDisplayActivity();\r
-             returnValue = true;\r
-             break;\r
-         default:\r
-               returnValue = super.onOptionsItemSelected(item);\r
-         }\r
-         \r
-         return returnValue;\r
-     }\r
\r
\r
\r
-     @Override\r
-     protected void onResume() {\r
-         \r
-         super.onResume();\r
-         if (!mConfigurationChangedToLandscape) { \r
-             FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
-             fragment.updateFileDetails(false);\r
-         }\r
-     }\r
-     \r
\r
-     private void backToDisplayActivity() {\r
-         Intent intent = new Intent(this, FileDisplayActivity.class);\r
-         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
-         intent.putExtra(FileDetailFragment.EXTRA_FILE, getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE));\r
-         intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT));\r
-         startActivity(intent);\r
-         finish();\r
-     }\r
-     \r
-     \r
-     @Override\r
-     protected Dialog onCreateDialog(int id) {\r
-         Dialog dialog = null;\r
-         switch (id) {\r
-         case DIALOG_SHORT_WAIT: {\r
-             ProgressDialog working_dialog = new ProgressDialog(this);\r
-             working_dialog.setMessage(getResources().getString(\r
-                     R.string.wait_a_moment));\r
-             working_dialog.setIndeterminate(true);\r
-             working_dialog.setCancelable(false);\r
-             dialog = working_dialog;\r
-             break;\r
-         }\r
-         default:\r
-             dialog = null;\r
-         }\r
-         return dialog;\r
-     }\r
-     \r
-     \r
-     /**\r
-      * {@inheritDoc}\r
-      */\r
-     @Override\r
-     public void onFileStateChanged() {\r
-         // nothing to do here!\r
-     }\r
\r
-     \r
-     /**\r
-      * {@inheritDoc}\r
-      */\r
-     @Override\r
-     public FileDownloaderBinder getFileDownloaderBinder() {\r
-         return mDownloaderBinder;\r
-     }\r
\r
\r
-     @Override\r
-     public FileUploaderBinder getFileUploaderBinder() {\r
-         return mUploaderBinder;\r
-     }\r
-     \r
- }\r
+ /* ownCloud Android client application
+  *   Copyright (C) 2011  Bartek Przybylski
+  *   Copyright (C) 2012-2013 ownCloud Inc.
+  *
+  *   This program is free software: you can redistribute it and/or modify
+  *   it under the terms of the GNU General Public License 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.accounts.Account;
+ import android.app.Dialog;
+ import android.app.ProgressDialog;
+ import android.content.BroadcastReceiver;
+ import android.content.ComponentName;
+ import android.content.Context;
+ import android.content.Intent;
+ import android.content.IntentFilter;
+ import android.content.ServiceConnection;
+ import android.content.res.Configuration;
+ 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;
+ import com.actionbarsherlock.view.MenuItem;
+ import com.owncloud.android.datamodel.FileDataStorageManager;
+ import com.owncloud.android.datamodel.OCFile;
+ import com.owncloud.android.files.services.FileDownloader;
+ import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+ import com.owncloud.android.files.services.FileUploader;
+ import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+ import com.owncloud.android.ui.fragment.FileDetailFragment;
+ import com.owncloud.android.ui.fragment.FileFragment;
+ import com.owncloud.android.ui.preview.PreviewMediaFragment;
+ import com.owncloud.android.AccountUtils;
+ import com.owncloud.android.Log_OC;
+ import com.owncloud.android.R;
+ /**
+  * This activity displays the details of a file like its name, its size and so
+  * on.
+  * 
+  * @author Bartek Przybylski
+  * @author David A. Velasco
+  */
+ public class FileDetailActivity extends SherlockFragmentActivity implements FileFragment.ContainerActivity {
+     
+     public static final int DIALOG_SHORT_WAIT = 0;
+     public static final String TAG = FileDetailActivity.class.getSimpleName();
+     
+     public static final String EXTRA_MODE = "MODE";
+     public static final int MODE_DETAILS = 0;
+     public static final int MODE_PREVIEW = 1;
+     public static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW";
+     
+     private boolean mConfigurationChangedToLandscape = false;
+     private FileDownloaderBinder mDownloaderBinder = null;
+     private ServiceConnection mDownloadConnection, mUploadConnection = null;
+     private FileUploaderBinder mUploaderBinder = null;
+     private boolean mWaitingToPreview;
+     
+     private OCFile mFile;
+     private Account mAccount;
+     private FileDataStorageManager mStorageManager;
+     private DownloadFinishReceiver mDownloadFinishReceiver;
+     
+     @Override
+     protected void onCreate(Bundle savedInstanceState) {
+         super.onCreate(savedInstanceState);
+         mFile = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);
+         mAccount = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);
+         mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
+         
+         // check if configuration changed to large-land ; for a tablet being changed from portrait to landscape when in FileDetailActivity 
+         Configuration conf = getResources().getConfiguration();
+         mConfigurationChangedToLandscape = (conf.orientation == Configuration.ORIENTATION_LANDSCAPE && 
+                                                 (conf.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE
+                                            );
+         if (!mConfigurationChangedToLandscape) {
+             setContentView(R.layout.file_activity_details);
+         
+             ActionBar actionBar = getSupportActionBar();
+             actionBar.setDisplayHomeAsUpEnabled(true);
+             if (savedInstanceState == null) {
+                 mWaitingToPreview = false;
+                 createChildFragment();
+             } else {
+                 mWaitingToPreview = savedInstanceState.getBoolean(KEY_WAITING_TO_PREVIEW);
+             }
+             
+             mDownloadConnection = new DetailsServiceConnection();
+             bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);
+             mUploadConnection = new DetailsServiceConnection();
+             bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);
+             
+             
+         }  else {
+             backToDisplayActivity(false);   // the 'back' won't be effective until this.onStart() and this.onResume() are completed;
+         }
+         
+     }
+     
+     /**
+      * Creates the proper fragment depending upon the state of the handled {@link OCFile} and
+      * the requested {@link Intent}.
+      */
+     private void createChildFragment() {
+         int mode = getIntent().getIntExtra(EXTRA_MODE, MODE_PREVIEW); 
+         
+         Fragment newFragment = null;
+         if (PreviewMediaFragment.canBePreviewed(mFile) && mode == MODE_PREVIEW) {
+             if (mFile.isDown()) {
+                 newFragment = new PreviewMediaFragment(mFile, mAccount);
+             
+             } else {
+                 newFragment = new FileDetailFragment(mFile, mAccount);
+                 mWaitingToPreview = true;
+             }
+             
+         } else {
+             newFragment = new FileDetailFragment(mFile, mAccount);
+         }
+         FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+         ft.replace(R.id.fragment, newFragment, FileDetailFragment.FTAG);
+         ft.commit();
+     }
+     
+     @Override
+     protected void onSaveInstanceState(Bundle outState) {
+         super.onSaveInstanceState(outState);
+         outState.putBoolean(KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
+     }
+     
+     
+     @Override
+     public void onPause() {
+         super.onPause();
+         if (mDownloadFinishReceiver != null) {
+             unregisterReceiver(mDownloadFinishReceiver);
+             mDownloadFinishReceiver = null;
+         }
+     }
+     
+     @Override
+     public void onResume() {
+         super.onResume();
+         if (!mConfigurationChangedToLandscape) {
+             // TODO this is probably unnecessary
+             Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+             if (fragment != null && fragment instanceof FileDetailFragment) {
+                 ((FileDetailFragment) fragment).updateFileDetails(false, false);
+             }
+         }
+         // Listen for download messages
+         IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_ADDED_MESSAGE);
+         downloadIntentFilter.addAction(FileDownloader.DOWNLOAD_FINISH_MESSAGE);
+         mDownloadFinishReceiver = new DownloadFinishReceiver();
+         registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
+     }
+     
+     
+     /** Defines callbacks for service binding, passed to bindService() */
+     private class DetailsServiceConnection implements ServiceConnection {
+         @Override
+         public void onServiceConnected(ComponentName component, IBinder service) {
+                 
+             if (component.equals(new ComponentName(FileDetailActivity.this, FileDownloader.class))) {
+                 Log_OC.d(TAG, "Download service connected");
+                 mDownloaderBinder = (FileDownloaderBinder) service;
+                 if (mWaitingToPreview) {
+                     requestForDownload();
+                 }
+                     
+             } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) {
+                 Log_OC.d(TAG, "Upload service connected");
+                 mUploaderBinder = (FileUploaderBinder) service;
+             } else {
+                 return;
+             }
+             
+             Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+             FileDetailFragment detailsFragment = (fragment instanceof FileDetailFragment) ? (FileDetailFragment) fragment : null;
+             if (detailsFragment != null) {
+                 detailsFragment.listenForTransferProgress();
+                 detailsFragment.updateFileDetails(mWaitingToPreview, false);   // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais())
+             }
+         }
+         @Override
+         public void onServiceDisconnected(ComponentName component) {
+             if (component.equals(new ComponentName(FileDetailActivity.this, FileDownloader.class))) {
+                 Log_OC.d(TAG, "Download service disconnected");
+                 mDownloaderBinder = null;
+             } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) {
+                 Log_OC.d(TAG, "Upload service disconnected");
+                 mUploaderBinder = null;
+             }
+         }
+     };    
+     
+     
+     @Override
+     public void onDestroy() {
+         super.onDestroy();
+         if (mDownloadConnection != null) {
+             unbindService(mDownloadConnection);
+             mDownloadConnection = null;
+         }
+         if (mUploadConnection != null) {
+             unbindService(mUploadConnection);
+             mUploadConnection = null;
+         }
+     }
+     
+     
+     @Override
+     public boolean onOptionsItemSelected(MenuItem item) {
+         boolean returnValue = false;
+         
+         switch(item.getItemId()){
+         case android.R.id.home:
+             backToDisplayActivity(true);
+             returnValue = true;
+             break;
+         default:
+             returnValue = super.onOptionsItemSelected(item);
+         }
+         
+         return returnValue;
+     }
+     private void backToDisplayActivity(boolean moveToParent) {
+         Intent intent = new Intent(this, FileDisplayActivity.class);
+         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+         OCFile targetFile = null;
+         if (mFile != null) {
+             targetFile = moveToParent ? mStorageManager.getFileById(mFile.getParentId()) : mFile;
+         }
+         intent.putExtra(FileDetailFragment.EXTRA_FILE, targetFile);
+         intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, mAccount);
+         startActivity(intent);
+         finish();
+     }
+     
+     
+     @Override
+     protected Dialog onCreateDialog(int id) {
+         Dialog dialog = null;
+         switch (id) {
+         case DIALOG_SHORT_WAIT: {
+             ProgressDialog working_dialog = new ProgressDialog(this);
+             working_dialog.setMessage(getResources().getString(
+                     R.string.wait_a_moment));
+             working_dialog.setIndeterminate(true);
+             working_dialog.setCancelable(false);
+             dialog = working_dialog;
+             break;
+         }
+         default:
+             dialog = null;
+         }
+         return dialog;
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onFileStateChanged() {
+         // nothing to do here!
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public FileDownloaderBinder getFileDownloaderBinder() {
+         return mDownloaderBinder;
+     }
+     @Override
+     public FileUploaderBinder getFileUploaderBinder() {
+         return mUploaderBinder;
+     }
+     @Override
+     public void showFragmentWithDetails(OCFile file) {
+         FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+         transaction.replace(R.id.fragment, new FileDetailFragment(file, mAccount), FileDetailFragment.FTAG); 
+         transaction.commit();
+     }
+     
+     private void requestForDownload() {
+         if (!mDownloaderBinder.isDownloading(mAccount, mFile)) {
+             Intent i = new Intent(this, FileDownloader.class);
+             i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount);
+             i.putExtra(FileDownloader.EXTRA_FILE, mFile);
+             startService(i);
+         }
+     }
+     
+     /**
+      * Class waiting for broadcast events from the {@link FielDownloader} service.
+      * 
+      * Updates the UI when a download is started or finished, provided that it is relevant for the
+      * current file.
+      */
+     private class DownloadFinishReceiver extends BroadcastReceiver {
+         @Override
+         public void onReceive(Context context, Intent intent) {
+             boolean sameAccount = isSameAccount(context, intent);
+             String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
+             boolean samePath = (mFile != null && mFile.getRemotePath().equals(downloadedRemotePath));
+             
+             if (sameAccount && samePath) {
+                 updateChildFragment(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false));
+             }
+             
+             removeStickyBroadcast(intent);
+         }
+         private boolean isSameAccount(Context context, Intent intent) {
+             String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
+             return (accountName != null && accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name));
+         }
+     }
+     public void updateChildFragment(String downloadEvent, String downloadedRemotePath, boolean success) {
+         Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+         if (fragment != null && fragment instanceof FileDetailFragment) {
+             FileDetailFragment detailsFragment = (FileDetailFragment) fragment;
+             OCFile fileInFragment = detailsFragment.getFile();
+             if (fileInFragment != null && !downloadedRemotePath.equals(fileInFragment.getRemotePath())) {
+                 // this never should happen; fileInFragment should be always equals to mFile, that was compared to downloadedRemotePath in DownloadReceiver 
+                 mWaitingToPreview = false;
+                 
+             } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_ADDED_MESSAGE)) {
+                 // grants that the progress bar is updated
+                 detailsFragment.listenForTransferProgress();
+                 detailsFragment.updateFileDetails(true, false);
+                 
+             } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_FINISH_MESSAGE)) {
+                 //  refresh the details fragment 
+                 if (success && mWaitingToPreview) {
+                     mFile = mStorageManager.getFileById(mFile.getFileId());   // update the file from database, for the local storage path
+                     FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+                     transaction.replace(R.id.fragment, new PreviewMediaFragment(mFile, mAccount), FileDetailFragment.FTAG);
+                     transaction.commit();
+                     mWaitingToPreview = false;
+                     
+                 } else {
+                     detailsFragment.updateFileDetails(false, (success));
+                     // TODO error message if !success Â¿?
+                 }
+             }
+         } // TODO else if (fragment != null && fragment )
+         
+     }
+ }
- /* ownCloud Android client application\r
-  *   Copyright (C) 2011  Bartek Przybylski\r
-  *   Copyright (C) 2012-2013 ownCloud Inc.\r
-  *\r
-  *   This program is free software: you can redistribute it and/or modify\r
-  *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 2 of the License, or\r
-  *   (at your option) any later version.\r
-  *\r
-  *   This program is distributed in the hope that it will be useful,\r
-  *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-  *   GNU General Public License for more details.\r
-  *\r
-  *   You should have received a copy of the GNU General Public License\r
-  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
-  *\r
-  */\r
\r
- package com.owncloud.android.ui.activity;\r
\r
- import java.io.File;\r
\r
- import android.accounts.Account;\r
- import android.app.AlertDialog;\r
- import android.app.ProgressDialog;\r
- import android.app.AlertDialog.Builder;\r
- import android.app.Dialog;\r
- import android.content.BroadcastReceiver;\r
- import android.content.ComponentName;\r
- import android.content.ContentResolver;\r
- import android.content.Context;\r
- import android.content.DialogInterface;\r
- import android.content.DialogInterface.OnClickListener;\r
- import android.content.Intent;\r
- import android.content.IntentFilter;\r
- import android.content.ServiceConnection;\r
- import android.content.SharedPreferences;\r
- import android.content.SharedPreferences.Editor;\r
- import android.content.pm.PackageInfo;\r
- import android.content.pm.PackageManager.NameNotFoundException;\r
- import android.content.res.Resources.NotFoundException;\r
- import android.database.Cursor;\r
- import android.graphics.Bitmap;\r
- import android.graphics.drawable.BitmapDrawable;\r
- import android.net.Uri;\r
- import android.os.Bundle;\r
- import android.os.Handler;\r
- import android.os.IBinder;\r
- import android.preference.PreferenceManager;\r
- import android.provider.MediaStore;\r
- import android.support.v4.app.FragmentTransaction;\r
- import android.util.Log;\r
- import android.view.View;\r
- import android.view.ViewGroup;\r
- import android.widget.ArrayAdapter;\r
- import android.widget.EditText;\r
- import android.widget.TextView;\r
- import android.widget.Toast;\r
\r
- import com.actionbarsherlock.app.ActionBar;\r
- import com.actionbarsherlock.app.ActionBar.OnNavigationListener;\r
- import com.actionbarsherlock.app.SherlockFragmentActivity;\r
- import com.actionbarsherlock.view.Menu;\r
- import com.actionbarsherlock.view.MenuInflater;\r
- import com.actionbarsherlock.view.MenuItem;\r
- import com.actionbarsherlock.view.Window;\r
- import com.owncloud.android.AccountUtils;\r
- import com.owncloud.android.authentication.AccountAuthenticator;\r
- import com.owncloud.android.datamodel.DataStorageManager;\r
- import com.owncloud.android.datamodel.FileDataStorageManager;\r
- import com.owncloud.android.datamodel.OCFile;\r
- import com.owncloud.android.files.services.FileDownloader;\r
- import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;\r
- import com.owncloud.android.files.services.FileObserverService;\r
- import com.owncloud.android.files.services.FileUploader;\r
- import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;\r
- import com.owncloud.android.operations.CreateFolderOperation;\r
- import com.owncloud.android.operations.OnRemoteOperationListener;\r
- import com.owncloud.android.operations.RemoteOperation;\r
- import com.owncloud.android.operations.RemoteOperationResult;\r
- import com.owncloud.android.operations.RemoveFileOperation;\r
- import com.owncloud.android.operations.RenameFileOperation;\r
- import com.owncloud.android.operations.SynchronizeFileOperation;\r
- import com.owncloud.android.operations.RemoteOperationResult.ResultCode;\r
- import com.owncloud.android.syncadapter.FileSyncService;\r
- import com.owncloud.android.ui.dialog.ChangelogDialog;\r
- import com.owncloud.android.ui.dialog.SslValidatorDialog;\r
- import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;\r
- import com.owncloud.android.ui.fragment.FileDetailFragment;\r
- import com.owncloud.android.ui.fragment.OCFileListFragment;\r
\r
- import com.owncloud.android.R;\r
\r
- /**\r
-  * Displays, what files the user has available in his ownCloud.\r
-  * \r
-  * @author Bartek Przybylski\r
-  * \r
-  */\r
\r
- public class FileDisplayActivity extends SherlockFragmentActivity implements\r
-     OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, OnRemoteOperationListener {\r
-     \r
-     private ArrayAdapter<String> mDirectories;\r
-     private OCFile mCurrentDir = null;\r
-     private OCFile mCurrentFile = null;\r
\r
-     private DataStorageManager mStorageManager;\r
-     private SyncBroadcastReceiver mSyncBroadcastReceiver;\r
-     private UploadFinishReceiver mUploadFinishReceiver;\r
-     private DownloadFinishReceiver mDownloadFinishReceiver;\r
-     private FileDownloaderBinder mDownloaderBinder = null;\r
-     private FileUploaderBinder mUploaderBinder = null;\r
-     private ServiceConnection mDownloadConnection = null, mUploadConnection = null;\r
-     private RemoteOperationResult mLastSslUntrustedServerResult = null;\r
-     \r
-     private OCFileListFragment mFileList;\r
-     \r
-     private boolean mDualPane;\r
-     private Handler mHandler;\r
-     \r
-     private static final int DIALOG_SETUP_ACCOUNT = 0;\r
-     private static final int DIALOG_CREATE_DIR = 1;\r
-     private static final int DIALOG_ABOUT_APP = 2;\r
-     public static final int DIALOG_SHORT_WAIT = 3;\r
-     private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 4;\r
-     private static final int DIALOG_SSL_VALIDATOR = 5;\r
-     private static final int DIALOG_CERT_NOT_SAVED = 6;\r
-     private static final String DIALOG_CHANGELOG_TAG = "DIALOG_CHANGELOG";\r
\r
-     \r
-     private static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;\r
-     private static final int ACTION_SELECT_MULTIPLE_FILES = 2;\r
-     \r
-     private static final String TAG = "FileDisplayActivity";\r
\r
-     private static int[] mMenuIdentifiersToPatch = {R.id.about_app};\r
-     \r
-     @Override\r
-     public void onCreate(Bundle savedInstanceState) {\r
-         Log.d(getClass().toString(), "onCreate() start");\r
-         super.onCreate(savedInstanceState);\r
-         \r
-         mHandler = new Handler();\r
\r
-         /// Load of parameters from received intent\r
-         Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);\r
-         if (account != null && AccountUtils.setCurrentOwnCloudAccount(this, account.name)) {\r
-             mCurrentDir = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); \r
-         }\r
-         \r
-         /// Load of saved instance state: keep this always before initDataFromCurrentAccount()\r
-         if(savedInstanceState != null) {\r
-             // TODO - test if savedInstanceState should take precedence over file in the intent ALWAYS (now), NEVER, or SOME TIMES\r
-             mCurrentDir = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE);\r
-         }\r
-         \r
-         if (!AccountUtils.accountsAreSetup(this)) {\r
-             /// no account available: FORCE ACCOUNT CREATION\r
-             mStorageManager = null;\r
-             createFirstAccount();\r
-             \r
-         } else {    /// at least an account is available\r
-             \r
-             initDataFromCurrentAccount();   // it checks mCurrentDir and mCurrentFile with the current account\r
-             \r
-         }\r
-         \r
-         mUploadConnection = new ListServiceConnection(); \r
-         mDownloadConnection = new ListServiceConnection();\r
-         bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);\r
-         bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);\r
\r
-         // PIN CODE request ;  best location is to decide, let's try this first\r
-         if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN) && savedInstanceState == null) {\r
-             requestPinCode();\r
-         }\r
\r
-         // file observer\r
-         Intent observer_intent = new Intent(this, FileObserverService.class);\r
-         observer_intent.putExtra(FileObserverService.KEY_FILE_CMD, FileObserverService.CMD_INIT_OBSERVED_LIST);\r
-         startService(observer_intent);\r
-         \r
-             \r
-         /// USER INTERFACE\r
-         requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);\r
-             \r
-         // Drop-down navigation \r
-         mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);\r
-         OCFile currFile = mCurrentDir;\r
-         while(mStorageManager != null && currFile != null && currFile.getFileName() != OCFile.PATH_SEPARATOR) {\r
-             mDirectories.add(currFile.getFileName());\r
-             currFile = mStorageManager.getFileById(currFile.getParentId());\r
-         }\r
-         mDirectories.add(OCFile.PATH_SEPARATOR);\r
\r
-         // Inflate and set the layout view\r
-         setContentView(R.layout.files);    \r
-         mFileList = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);\r
-         mDualPane = (findViewById(R.id.file_details_container) != null);\r
-         if (mDualPane) {\r
-             initFileDetailsInDualPane();\r
-         }\r
-             \r
-         // Action bar setup\r
-         ActionBar actionBar = getSupportActionBar();\r
-         actionBar.setHomeButtonEnabled(true);   // mandatory since Android ICS, according to the official documentation\r
-         actionBar.setDisplayHomeAsUpEnabled(mCurrentDir != null && mCurrentDir.getParentId() != 0);\r
-         actionBar.setDisplayShowTitleEnabled(false);\r
-         actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);\r
-         actionBar.setListNavigationCallbacks(mDirectories, this);\r
-         setSupportProgressBarIndeterminateVisibility(false);        // always AFTER setContentView(...) ; to workaround bug in its implementation\r
-         \r
-         \r
-         // show changelog, if needed\r
-         //showChangeLog();\r
-         \r
-         Log.d(getClass().toString(), "onCreate() end");\r
-     }\r
\r
-     \r
-     /**\r
-      * Shows a dialog with the change log of the current version after each app update\r
-      * \r
-      *  TODO make it permanent; by now, only to advice the workaround app for 4.1.x\r
-      */\r
-     private void showChangeLog() {\r
-         if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.JELLY_BEAN) {\r
-             final String KEY_VERSION = "version";\r
-             SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());\r
-             int currentVersionNumber = 0;\r
-             int savedVersionNumber = sharedPref.getInt(KEY_VERSION, 0);\r
-             try {\r
-                 PackageInfo pi          = getPackageManager().getPackageInfo(getPackageName(), 0);\r
-                 currentVersionNumber    = pi.versionCode;\r
-             } catch (Exception e) {}\r
-      \r
-             if (currentVersionNumber > savedVersionNumber) {\r
-                 ChangelogDialog.newInstance(true).show(getSupportFragmentManager(), DIALOG_CHANGELOG_TAG);\r
-                 Editor editor   = sharedPref.edit();\r
-                 editor.putInt(KEY_VERSION, currentVersionNumber);\r
-                 editor.commit();\r
-             }\r
-         }\r
-     }\r
-     \r
\r
-     /**\r
-      * Launches the account creation activity. To use when no ownCloud account is available\r
-      */\r
-     private void createFirstAccount() {\r
-         Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);\r
-         intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTHORITY });\r
-         startActivity(intent);  // the new activity won't be created until this.onStart() and this.onResume() are finished;\r
-     }\r
\r
\r
-     /**\r
-      *  Load of state dependent of the existence of an ownCloud account\r
-      */\r
-     private void initDataFromCurrentAccount() {\r
-         /// Storage manager initialization - access to local database\r
-         mStorageManager = new FileDataStorageManager(\r
-                 AccountUtils.getCurrentOwnCloudAccount(this),\r
-                 getContentResolver());\r
\r
-         /// Check if mCurrentDir is a directory\r
-         if(mCurrentDir != null && !mCurrentDir.isDirectory()) {\r
-             mCurrentFile = mCurrentDir;\r
-             mCurrentDir = mStorageManager.getFileById(mCurrentDir.getParentId());\r
-         }\r
-         \r
-         /// Check if mCurrentDir and mCurrentFile are in the current account, and update them\r
-         if (mCurrentDir != null) {\r
-             mCurrentDir = mStorageManager.getFileByPath(mCurrentDir.getRemotePath());   // mCurrentDir == null if it is not in the current account\r
-         }\r
-         if (mCurrentFile != null) {\r
-             if (mCurrentFile.fileExists()) {\r
-                 mCurrentFile = mStorageManager.getFileByPath(mCurrentFile.getRemotePath());   // mCurrentFile == null if it is not in the current account\r
-             }   // else : keep mCurrentFile with the received value; this is currently the case of an upload in progress, when the user presses the status notification in a landscape tablet\r
-         }\r
-         \r
-         /// Default to root if mCurrentDir was not found\r
-         if (mCurrentDir == null) {\r
-             mCurrentDir = mStorageManager.getFileByPath("/"); // will be NULL if the database was never synchronized\r
-         }\r
-     }\r
-         \r
-     \r
-     private void initFileDetailsInDualPane() {\r
-         if (mDualPane && getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG) == null) {\r
-             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
-             if (mCurrentFile != null) {\r
-                 transaction.replace(R.id.file_details_container, new FileDetailFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG); // empty FileDetailFragment\r
-                 mCurrentFile = null;\r
-             } else {\r
-                 transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment\r
-             }\r
-             transaction.commit();\r
-         }\r
-     }\r
-     \r
-     \r
-     @Override\r
-     public void onDestroy() {\r
-         super.onDestroy();\r
-         if (mDownloadConnection != null)\r
-             unbindService(mDownloadConnection);\r
-         if (mUploadConnection != null)\r
-             unbindService(mUploadConnection);\r
-     }\r
\r
-     \r
-     @Override\r
-     public boolean onCreateOptionsMenu(Menu menu) {\r
-         MenuInflater inflater = getSherlock().getMenuInflater();\r
-             inflater.inflate(R.menu.menu, menu);\r
-             \r
-             patchHiddenAccents(menu);\r
-             \r
-             return true;\r
-     }\r
\r
-     /**\r
-      * Workaround for this: <a href="http://code.google.com/p/android/issues/detail?id=3974">http://code.google.com/p/android/issues/detail?id=3974</a> \r
-      * \r
-      * @param menu      Menu to patch\r
-      */\r
-     private void patchHiddenAccents(Menu menu) {\r
-         for (int i = 0; i < mMenuIdentifiersToPatch.length ; i++) {\r
-             MenuItem aboutItem = menu.findItem(mMenuIdentifiersToPatch[i]);\r
-             if (aboutItem != null && aboutItem.getIcon() instanceof BitmapDrawable) {\r
-                 // Clip off the bottom three (density independent) pixels of transparent padding\r
-                 Bitmap original = ((BitmapDrawable) aboutItem.getIcon()).getBitmap();\r
-                 float scale = getResources().getDisplayMetrics().density;\r
-                 int clippedHeight = (int) (original.getHeight() - (3 * scale));\r
-                 Bitmap scaled = Bitmap.createBitmap(original, 0, 0, original.getWidth(), clippedHeight);\r
-                 aboutItem.setIcon(new BitmapDrawable(getResources(), scaled));\r
-             }\r
-         }\r
-     }\r
\r
\r
-     @Override\r
-     public boolean onOptionsItemSelected(MenuItem item) {\r
-         boolean retval = true;\r
-         switch (item.getItemId()) {\r
-             case R.id.createDirectoryItem: {\r
-                 showDialog(DIALOG_CREATE_DIR);\r
-                 break;\r
-             }\r
-             case R.id.startSync: {\r
-                 startSynchronization();\r
-                 break;\r
-             }\r
-             case R.id.action_upload: {\r
-                 showDialog(DIALOG_CHOOSE_UPLOAD_SOURCE);\r
-                 break;\r
-             }\r
-             case R.id.action_settings: {\r
-                 Intent settingsIntent = new Intent(this, Preferences.class);\r
-                 startActivity(settingsIntent);\r
-                 break;\r
-             }\r
-             case R.id.about_app : {\r
-                 showDialog(DIALOG_ABOUT_APP);\r
-                 break;\r
-             }\r
-             case android.R.id.home: {\r
-                 if(mCurrentDir != null && mCurrentDir.getParentId() != 0){\r
-                     onBackPressed(); \r
-                 }\r
-                 break;\r
-             }\r
-             default:\r
-                 retval = super.onOptionsItemSelected(item);\r
-         }\r
-         return retval;\r
-     }\r
\r
-     private void startSynchronization() {\r
-         ContentResolver.cancelSync(null, AccountAuthenticator.AUTHORITY);   // cancel the current synchronizations of any ownCloud account\r
-         Bundle bundle = new Bundle();\r
-         bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);\r
-         ContentResolver.requestSync(\r
-                 AccountUtils.getCurrentOwnCloudAccount(this),\r
-                 AccountAuthenticator.AUTHORITY, bundle);\r
-     }\r
\r
\r
-     @Override\r
-     public boolean onNavigationItemSelected(int itemPosition, long itemId) {\r
-         int i = itemPosition;\r
-         while (i-- != 0) {\r
-             onBackPressed();\r
-         }\r
-         // the next operation triggers a new call to this method, but it's necessary to \r
-         // ensure that the name exposed in the action bar is the current directory when the \r
-         // user selected it in the navigation list\r
-         if (itemPosition != 0)\r
-             getSupportActionBar().setSelectedNavigationItem(0);\r
-         return true;\r
-     }\r
\r
-     /**\r
-      * Called, when the user selected something for uploading\r
-      */\r
-     public void onActivityResult(int requestCode, int resultCode, Intent data) {\r
-         \r
-         if (requestCode == ACTION_SELECT_CONTENT_FROM_APPS && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {\r
-             requestSimpleUpload(data, resultCode);\r
-             \r
-         } else if (requestCode == ACTION_SELECT_MULTIPLE_FILES && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {\r
-             requestMultipleUpload(data, resultCode);\r
-             \r
-         }\r
-     }\r
\r
-     private void requestMultipleUpload(Intent data, int resultCode) {\r
-         String[] filePaths = data.getStringArrayExtra(UploadFilesActivity.EXTRA_CHOSEN_FILES);\r
-         if (filePaths != null) {\r
-             String[] remotePaths = new String[filePaths.length];\r
-             String remotePathBase = "";\r
-             for (int j = mDirectories.getCount() - 2; j >= 0; --j) {\r
-                 remotePathBase += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);\r
-             }\r
-             if (!remotePathBase.endsWith(OCFile.PATH_SEPARATOR))\r
-                 remotePathBase += OCFile.PATH_SEPARATOR;\r
-             for (int j = 0; j< remotePaths.length; j++) {\r
-                 remotePaths[j] = remotePathBase + (new File(filePaths[j])).getName();\r
-             }\r
\r
-             Intent i = new Intent(this, FileUploader.class);\r
-             i.putExtra(FileUploader.KEY_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));\r
-             i.putExtra(FileUploader.KEY_LOCAL_FILE, filePaths);\r
-             i.putExtra(FileUploader.KEY_REMOTE_FILE, remotePaths);\r
-             i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);\r
-             if (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)\r
-                 i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE);\r
-             startService(i);\r
-             \r
-         } else {\r
-             Log.d("FileDisplay", "User clicked on 'Update' with no selection");\r
-             Toast t = Toast.makeText(this, getString(R.string.filedisplay_no_file_selected), Toast.LENGTH_LONG);\r
-             t.show();\r
-             return;\r
-         }\r
-     }\r
\r
\r
-     private void requestSimpleUpload(Intent data, int resultCode) {\r
-         String filepath = null;\r
-         try {\r
-             Uri selectedImageUri = data.getData();\r
\r
-             String filemanagerstring = selectedImageUri.getPath();\r
-             String selectedImagePath = getPath(selectedImageUri);\r
\r
-             if (selectedImagePath != null)\r
-                 filepath = selectedImagePath;\r
-             else\r
-                 filepath = filemanagerstring;\r
-             \r
-         } catch (Exception e) {\r
-             Log.e("FileDisplay", "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e);\r
-             e.printStackTrace();\r
-             \r
-         } finally {\r
-             if (filepath == null) {\r
-                 Log.e("FileDisplay", "Couldnt resolve path to file");\r
-                 Toast t = Toast.makeText(this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG);\r
-                 t.show();\r
-                 return;\r
-             }\r
-         }\r
\r
-         Intent i = new Intent(this, FileUploader.class);\r
-         i.putExtra(FileUploader.KEY_ACCOUNT,\r
-                 AccountUtils.getCurrentOwnCloudAccount(this));\r
-         String remotepath = new String();\r
-         for (int j = mDirectories.getCount() - 2; j >= 0; --j) {\r
-             remotepath += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);\r
-         }\r
-         if (!remotepath.endsWith(OCFile.PATH_SEPARATOR))\r
-             remotepath += OCFile.PATH_SEPARATOR;\r
-         remotepath += new File(filepath).getName();\r
\r
-         i.putExtra(FileUploader.KEY_LOCAL_FILE, filepath);\r
-         i.putExtra(FileUploader.KEY_REMOTE_FILE, remotepath);\r
-         i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);\r
-         if (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)\r
-             i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE);\r
-         startService(i);\r
-     }\r
\r
\r
-     @Override\r
-     public void onBackPressed() {\r
-         if (mDirectories.getCount() <= 1) {\r
-             finish();\r
-             return;\r
-         }\r
-         popDirname();\r
-         mFileList.onNavigateUp();\r
-         mCurrentDir = mFileList.getCurrentFile();\r
-         \r
-         if (mDualPane) {\r
-             // Resets the FileDetailsFragment on Tablets so that it always displays\r
-             FileDetailFragment fileDetails = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
-             if (fileDetails != null && !fileDetails.isEmpty()) {\r
-                 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
-                 transaction.remove(fileDetails);\r
-                 transaction.add(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG);\r
-                 transaction.commit();\r
-             }\r
-         }\r
-         \r
-         if(mCurrentDir.getParentId() == 0){\r
-             ActionBar actionBar = getSupportActionBar(); \r
-             actionBar.setDisplayHomeAsUpEnabled(false);\r
-         } \r
-     }\r
\r
-     @Override\r
-     protected void onSaveInstanceState(Bundle outState) {\r
-         // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved\r
-         Log.d(getClass().toString(), "onSaveInstanceState() start");\r
-         super.onSaveInstanceState(outState);\r
-         outState.putParcelable(FileDetailFragment.EXTRA_FILE, mCurrentDir);\r
-         if (mDualPane) {\r
-             FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
-             if (fragment != null) {\r
-                 OCFile file = fragment.getDisplayedFile();\r
-                 if (file != null) {\r
-                     outState.putParcelable(FileDetailFragment.EXTRA_FILE, file);\r
-                 }\r
-             }\r
-         }\r
-         Log.d(getClass().toString(), "onSaveInstanceState() end");\r
-     }\r
\r
-     @Override\r
-     protected void onResume() {\r
-         Log.d(getClass().toString(), "onResume() start");\r
-         super.onResume();\r
\r
-         if (AccountUtils.accountsAreSetup(this)) {\r
-             \r
-             if (mStorageManager == null) {\r
-                 // this is necessary for handling the come back to FileDisplayActivity when the first ownCloud account is created \r
-                 initDataFromCurrentAccount();\r
-                 if (mDualPane) {\r
-                     initFileDetailsInDualPane();\r
-                 }\r
-             }\r
-             \r
-             // Listen for sync messages\r
-             IntentFilter syncIntentFilter = new IntentFilter(FileSyncService.SYNC_MESSAGE);\r
-             mSyncBroadcastReceiver = new SyncBroadcastReceiver();\r
-             registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);\r
-             \r
-             // Listen for upload messages\r
-             IntentFilter uploadIntentFilter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);\r
-             mUploadFinishReceiver = new UploadFinishReceiver();\r
-             registerReceiver(mUploadFinishReceiver, uploadIntentFilter);\r
-             \r
-             // Listen for download messages\r
-             IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_FINISH_MESSAGE);\r
-             mDownloadFinishReceiver = new DownloadFinishReceiver();\r
-             registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);\r
-         \r
-             // List current directory\r
-             mFileList.listDirectory(mCurrentDir);   // TODO we should find the way to avoid the need of this (maybe it's not necessary yet; to check)\r
-             \r
-         } else {\r
-             \r
-             mStorageManager = null;     // an invalid object will be there if all the ownCloud accounts are removed\r
-             showDialog(DIALOG_SETUP_ACCOUNT);\r
-             \r
-         }\r
-         Log.d(getClass().toString(), "onResume() end");\r
-     }\r
\r
-     \r
-     @Override\r
-     protected void onPause() {\r
-         Log.d(getClass().toString(), "onPause() start");\r
-         super.onPause();\r
-         if (mSyncBroadcastReceiver != null) {\r
-             unregisterReceiver(mSyncBroadcastReceiver);\r
-             mSyncBroadcastReceiver = null;\r
-         }\r
-         if (mUploadFinishReceiver != null) {\r
-             unregisterReceiver(mUploadFinishReceiver);\r
-             mUploadFinishReceiver = null;\r
-         }\r
-         if (mDownloadFinishReceiver != null) {\r
-             unregisterReceiver(mDownloadFinishReceiver);\r
-             mDownloadFinishReceiver = null;\r
-         }\r
-         if (!AccountUtils.accountsAreSetup(this)) {\r
-             dismissDialog(DIALOG_SETUP_ACCOUNT);\r
-         }\r
-         \r
-         Log.d(getClass().toString(), "onPause() end");\r
-     }\r
\r
-     \r
-     @Override\r
-     protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {\r
-         if (id == DIALOG_SSL_VALIDATOR && mLastSslUntrustedServerResult != null) {\r
-             ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);\r
-         }\r
-     }\r
\r
-     \r
-     @Override\r
-     protected Dialog onCreateDialog(int id) {\r
-         Dialog dialog = null;\r
-         AlertDialog.Builder builder;\r
-         switch (id) {\r
-         case DIALOG_SETUP_ACCOUNT: {\r
-             builder = new AlertDialog.Builder(this);\r
-             builder.setTitle(R.string.main_tit_accsetup);\r
-             builder.setMessage(R.string.main_wrn_accsetup);\r
-             builder.setCancelable(false);\r
-             builder.setPositiveButton(android.R.string.ok, new OnClickListener() {\r
-                 public void onClick(DialogInterface dialog, int which) {\r
-                     createFirstAccount();\r
-                     dialog.dismiss();\r
-                 }\r
-             });\r
-             String message = String.format(getString(R.string.common_exit), getString(R.string.app_name));\r
-             builder.setNegativeButton(message, new OnClickListener() {\r
-                 public void onClick(DialogInterface dialog, int which) {\r
-                     dialog.dismiss();\r
-                     finish();\r
-                 }\r
-             });\r
-             //builder.setNegativeButton(android.R.string.cancel, this);\r
-             dialog = builder.create();\r
-             break;\r
-         }\r
-         case DIALOG_ABOUT_APP: {\r
-             builder = new AlertDialog.Builder(this);\r
-             builder.setTitle(getString(R.string.about_title));\r
-             PackageInfo pkg;\r
-             try {\r
-                 pkg = getPackageManager().getPackageInfo(getPackageName(), 0);\r
-                 builder.setMessage(String.format(getString(R.string.about_message), getString(R.string.app_name), pkg.versionName));\r
-                 builder.setIcon(android.R.drawable.ic_menu_info_details);\r
-                 dialog = builder.create();\r
-             } catch (NameNotFoundException e) {\r
-                 builder = null;\r
-                 dialog = null;\r
-                 Log.e(TAG, "Error while showing about dialog", e);\r
-             }\r
-             break;\r
-         }\r
-         case DIALOG_CREATE_DIR: {\r
-             builder = new Builder(this);\r
-             final EditText dirNameInput = new EditText(getBaseContext());\r
-             builder.setView(dirNameInput);\r
-             builder.setTitle(R.string.uploader_info_dirname);\r
-             int typed_color = getResources().getColor(R.color.setup_text_typed);\r
-             dirNameInput.setTextColor(typed_color);\r
-             builder.setPositiveButton(android.R.string.ok,\r
-                     new OnClickListener() {\r
-                         public void onClick(DialogInterface dialog, int which) {\r
-                             String directoryName = dirNameInput.getText().toString();\r
-                             if (directoryName.trim().length() == 0) {\r
-                                 dialog.cancel();\r
-                                 return;\r
-                             }\r
-     \r
-                             // Figure out the path where the dir needs to be created\r
-                             String path;\r
-                             if (mCurrentDir == null) {\r
-                                 // this is just a patch; we should ensure that mCurrentDir never is null\r
-                                 if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) {\r
-                                     OCFile file = new OCFile(OCFile.PATH_SEPARATOR);\r
-                                     mStorageManager.saveFile(file);\r
-                                 }\r
-                                 mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);\r
-                             }\r
-                             path = FileDisplayActivity.this.mCurrentDir.getRemotePath();\r
-                             \r
-                             // Create directory\r
-                             path += directoryName + OCFile.PATH_SEPARATOR;\r
-                             RemoteOperation operation = new CreateFolderOperation(path, mCurrentDir.getFileId(), mStorageManager);\r
-                             operation.execute(  AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), \r
-                                                 FileDisplayActivity.this, \r
-                                                 FileDisplayActivity.this, \r
-                                                 mHandler,\r
-                                                 FileDisplayActivity.this);\r
-                             \r
-                             dialog.dismiss();\r
-                             \r
-                             showDialog(DIALOG_SHORT_WAIT);\r
-                         }\r
-                     });\r
-             builder.setNegativeButton(R.string.common_cancel,\r
-                     new OnClickListener() {\r
-                         public void onClick(DialogInterface dialog, int which) {\r
-                             dialog.cancel();\r
-                         }\r
-                     });\r
-             dialog = builder.create();\r
-             break;\r
-         }\r
-         case DIALOG_SHORT_WAIT: {\r
-             ProgressDialog working_dialog = new ProgressDialog(this);\r
-             working_dialog.setMessage(getResources().getString(\r
-                     R.string.wait_a_moment));\r
-             working_dialog.setIndeterminate(true);\r
-             working_dialog.setCancelable(false);\r
-             dialog = working_dialog;\r
-             break;\r
-         }\r
-         case DIALOG_CHOOSE_UPLOAD_SOURCE: {\r
-             final String [] items = {   getString(R.string.actionbar_upload_files), \r
-                                         getString(R.string.actionbar_upload_from_apps) }; \r
-             builder = new AlertDialog.Builder(this);\r
-             builder.setTitle(R.string.actionbar_upload);\r
-             builder.setItems(items, new DialogInterface.OnClickListener() {\r
-                 public void onClick(DialogInterface dialog, int item) {\r
-                     if (item == 0) {\r
-                         //if (!mDualPane) { \r
-                             Intent action = new Intent(FileDisplayActivity.this, UploadFilesActivity.class);\r
-                             action.putExtra(UploadFilesActivity.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this));\r
-                             startActivityForResult(action, ACTION_SELECT_MULTIPLE_FILES);\r
-                         //} else {\r
-                             // TODO create and handle new fragment LocalFileListFragment\r
-                         //}\r
-                     } else if (item == 1) {\r
-                         Intent action = new Intent(Intent.ACTION_GET_CONTENT);\r
-                         action = action.setType("*/*")\r
-                                 .addCategory(Intent.CATEGORY_OPENABLE);\r
-                         startActivityForResult(\r
-                                 Intent.createChooser(action, getString(R.string.upload_chooser_title)),\r
-                                 ACTION_SELECT_CONTENT_FROM_APPS);\r
-                     }\r
-                 }\r
-             });\r
-             dialog = builder.create();\r
-             break;\r
-         }\r
-         case DIALOG_SSL_VALIDATOR: {\r
-             dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);\r
-             break;\r
-         }\r
-         case DIALOG_CERT_NOT_SAVED: {\r
-             builder = new AlertDialog.Builder(this);\r
-             builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));\r
-             builder.setCancelable(false);\r
-             builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {\r
-                     @Override\r
-                     public void onClick(DialogInterface dialog, int which) {\r
-                         dialog.dismiss();\r
-                     };\r
-                 });\r
-             dialog = builder.create();\r
-             break;\r
-         }\r
-         default:\r
-             dialog = null;\r
-         }\r
-     \r
-         return dialog;\r
-     }\r
\r
-     \r
-     /**\r
-      * Translates a content URI of an image to a physical path\r
-      * on the disk\r
-      * @param uri The URI to resolve\r
-      * @return The path to the image or null if it could not be found\r
-      */\r
-     public String getPath(Uri uri) {\r
-         String[] projection = { MediaStore.Images.Media.DATA };\r
-         Cursor cursor = managedQuery(uri, projection, null, null, null);\r
-         if (cursor != null) {\r
-             int column_index = cursor\r
-                     .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);\r
-             cursor.moveToFirst();\r
-             return cursor.getString(column_index);\r
-         } \r
-         return null;\r
-     }\r
-     \r
-     /**\r
-      * Pushes a directory to the drop down list\r
-      * @param directory to push\r
-      * @throws IllegalArgumentException If the {@link OCFile#isDirectory()} returns false.\r
-      */\r
-     public void pushDirname(OCFile directory) {\r
-         if(!directory.isDirectory()){\r
-             throw new IllegalArgumentException("Only directories may be pushed!");\r
-         }\r
-         mDirectories.insert(directory.getFileName(), 0);\r
-         mCurrentDir = directory;\r
-     }\r
\r
-     /**\r
-      * Pops a directory name from the drop down list\r
-      * @return True, unless the stack is empty\r
-      */\r
-     public boolean popDirname() {\r
-         mDirectories.remove(mDirectories.getItem(0));\r
-         return !mDirectories.isEmpty();\r
-     }\r
\r
\r
-     // Custom array adapter to override text colors\r
-     private class CustomArrayAdapter<T> extends ArrayAdapter<T> {\r
-     \r
-         public CustomArrayAdapter(FileDisplayActivity ctx, int view) {\r
-             super(ctx, view);\r
-         }\r
-     \r
-         public View getView(int position, View convertView, ViewGroup parent) {\r
-             View v = super.getView(position, convertView, parent);\r
-     \r
-             ((TextView) v).setTextColor(getResources().getColorStateList(\r
-                     android.R.color.white));\r
-             return v;\r
-         }\r
-     \r
-         public View getDropDownView(int position, View convertView,\r
-                 ViewGroup parent) {\r
-             View v = super.getDropDownView(position, convertView, parent);\r
-     \r
-             ((TextView) v).setTextColor(getResources().getColorStateList(\r
-                     android.R.color.white));\r
-     \r
-             return v;\r
-         }\r
-     \r
-     }\r
\r
-     private class SyncBroadcastReceiver extends BroadcastReceiver {\r
\r
-         /**\r
-          * {@link BroadcastReceiver} to enable syncing feedback in UI\r
-          */\r
-         @Override\r
-         public void onReceive(Context context, Intent intent) {\r
-             boolean inProgress = intent.getBooleanExtra(\r
-                     FileSyncService.IN_PROGRESS, false);\r
-             String accountName = intent\r
-                     .getStringExtra(FileSyncService.ACCOUNT_NAME);\r
\r
-             Log.d("FileDisplay", "sync of account " + accountName\r
-                     + " is in_progress: " + inProgress);\r
\r
-             if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name)) {  \r
-             \r
-                 String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH); \r
-                  \r
-                 boolean fillBlankRoot = false;\r
-                 if (mCurrentDir == null) {\r
-                     mCurrentDir = mStorageManager.getFileByPath("/");\r
-                     fillBlankRoot = (mCurrentDir != null);\r
-                 }\r
\r
-                 if ((synchFolderRemotePath != null && mCurrentDir != null && (mCurrentDir.getRemotePath().equals(synchFolderRemotePath)))\r
-                         || fillBlankRoot ) {\r
-                     if (!fillBlankRoot) \r
-                         mCurrentDir = getStorageManager().getFileByPath(synchFolderRemotePath);\r
-                     OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager()\r
-                             .findFragmentById(R.id.fileList);\r
-                     if (fileListFragment != null) {\r
-                         fileListFragment.listDirectory(mCurrentDir);\r
-                     }\r
-                 }\r
-                 \r
-                 setSupportProgressBarIndeterminateVisibility(inProgress);\r
-                 removeStickyBroadcast(intent);\r
-                 \r
-             }\r
-             \r
-             RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncService.SYNC_RESULT);\r
-             if (synchResult != null) {\r
-                 if (synchResult.getCode().equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) {\r
-                     mLastSslUntrustedServerResult = synchResult;\r
-                     showDialog(DIALOG_SSL_VALIDATOR); \r
-                 }\r
-             }\r
-         }\r
-     }\r
-     \r
\r
-     private class UploadFinishReceiver extends BroadcastReceiver {\r
-         /**\r
-          * Once the file upload has finished -> update view\r
-          *  @author David A. Velasco\r
-          * {@link BroadcastReceiver} to enable upload feedback in UI\r
-          */\r
-         @Override\r
-         public void onReceive(Context context, Intent intent) {\r
-             String uploadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);\r
-             String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);\r
-             boolean sameAccount = accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name);\r
-             boolean isDescendant = (mCurrentDir != null) && (uploadedRemotePath != null) && (uploadedRemotePath.startsWith(mCurrentDir.getRemotePath()));\r
-             if (sameAccount && isDescendant) {\r
-                 OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);\r
-                 if (fileListFragment != null) { \r
-                     fileListFragment.listDirectory();\r
-                 }\r
-             }\r
-         }\r
-         \r
-     }\r
-     \r
-     \r
-     /**\r
-      * Once the file download has finished -> update view\r
-      */\r
-     private class DownloadFinishReceiver extends BroadcastReceiver {\r
-         @Override\r
-         public void onReceive(Context context, Intent intent) {\r
-             String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);\r
-             String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);\r
-             boolean sameAccount = accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name);\r
-             boolean isDescendant = (mCurrentDir != null) && (downloadedRemotePath != null) && (downloadedRemotePath.startsWith(mCurrentDir.getRemotePath()));\r
-             if (sameAccount && isDescendant) {\r
-                 OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);\r
-                 if (fileListFragment != null) { \r
-                     fileListFragment.listDirectory();\r
-                 }\r
-             }\r
-         }\r
-     }\r
-     \r
-     \r
-     \r
-     \r
-     /**\r
-      * {@inheritDoc}\r
-      */\r
-     @Override\r
-     public DataStorageManager getStorageManager() {\r
-         return mStorageManager;\r
-     }\r
-     \r
-     \r
-     /**\r
-      * {@inheritDoc}\r
-      */\r
-     @Override\r
-     public void onDirectoryClick(OCFile directory) {\r
-         pushDirname(directory);\r
-         ActionBar actionBar = getSupportActionBar();\r
-         actionBar.setDisplayHomeAsUpEnabled(true);\r
-         \r
-         if (mDualPane) {\r
-             // Resets the FileDetailsFragment on Tablets so that it always displays\r
-             FileDetailFragment fileDetails = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
-             if (fileDetails != null && !fileDetails.isEmpty()) {\r
-                 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
-                 transaction.remove(fileDetails);\r
-                 transaction.add(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG);\r
-                 transaction.commit();\r
-             }\r
-         }\r
-     }\r
-     \r
-     \r
-     /**\r
-      * {@inheritDoc}\r
-      */\r
-     @Override\r
-     public void onFileClick(OCFile file) {\r
-         \r
-         // If we are on a large device -> update fragment\r
-         if (mDualPane) {\r
-             // buttons in the details view are problematic when trying to reuse an existing fragment; create always a new one solves some of them, BUT no all; downloads are 'dangerous'\r
-             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
-             transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);\r
-             transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);\r
-             transaction.commit();\r
-             \r
-         } else {    // small or medium screen device -> new Activity\r
-             Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);\r
-             showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);\r
-             showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));\r
-             startActivity(showDetailsIntent);\r
-         }\r
-     }\r
-     \r
-     \r
-     /**\r
-      * {@inheritDoc}\r
-      */\r
-     @Override\r
-     public OCFile getInitialDirectory() {\r
-         return mCurrentDir;\r
-     }\r
-     \r
-     \r
-     /**\r
-      * {@inheritDoc}\r
-      */\r
-     @Override\r
-     public void onFileStateChanged() {\r
-         OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);\r
-         if (fileListFragment != null) { \r
-             fileListFragment.listDirectory();\r
-         }\r
-     }\r
\r
-     \r
-     /**\r
-      * {@inheritDoc}\r
-      */\r
-     @Override\r
-     public FileDownloaderBinder getFileDownloaderBinder() {\r
-         return mDownloaderBinder;\r
-     }\r
\r
-     \r
-     /**\r
-      * {@inheritDoc}\r
-      */\r
-     @Override\r
-     public FileUploaderBinder getFileUploaderBinder() {\r
-         return mUploaderBinder;\r
-     }\r
-     \r
-     \r
-     /** Defines callbacks for service binding, passed to bindService() */\r
-     private class ListServiceConnection implements ServiceConnection {\r
\r
-         @Override\r
-         public void onServiceConnected(ComponentName component, IBinder service) {\r
-             if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {\r
-                 Log.d(TAG, "Download service connected");\r
-                 mDownloaderBinder = (FileDownloaderBinder) service;\r
-             } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {\r
-                 Log.d(TAG, "Upload service connected");\r
-                 mUploaderBinder = (FileUploaderBinder) service;\r
-             } else {\r
-                 return;\r
-             }\r
-             // a new chance to get the mDownloadBinder through getFileDownloadBinder() - THIS IS A MESS\r
-             if (mFileList != null)\r
-                 mFileList.listDirectory();\r
-             if (mDualPane) {\r
-                 FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
-                 if (fragment != null)\r
-                     fragment.updateFileDetails(false);\r
-             }\r
-         }\r
\r
-         @Override\r
-         public void onServiceDisconnected(ComponentName component) {\r
-             if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {\r
-                 Log.d(TAG, "Download service disconnected");\r
-                 mDownloaderBinder = null;\r
-             } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {\r
-                 Log.d(TAG, "Upload service disconnected");\r
-                 mUploaderBinder = null;\r
-             }\r
-         }\r
-     };    \r
\r
-     \r
-     \r
-     /**\r
-      * Launch an intent to request the PIN code to the user before letting him use the app\r
-      */\r
-     private void requestPinCode() {\r
-         boolean pinStart = false;\r
-         SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());\r
-         pinStart = appPrefs.getBoolean("set_pincode", false);\r
-         if (pinStart) {\r
-             Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);\r
-             i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "FileDisplayActivity");\r
-             startActivity(i);\r
-         }\r
-     }\r
\r
\r
-     @Override\r
-     public void onSavedCertificate() {\r
-         startSynchronization();                \r
-     }\r
\r
\r
-     @Override\r
-     public void onFailedSavingCertificate() {\r
-         showDialog(DIALOG_CERT_NOT_SAVED);\r
-     }\r
\r
\r
-     /**\r
-      * Updates the view associated to the activity after the finish of some operation over files\r
-      * in the current account.\r
-      * \r
-      * @param operation     Removal operation performed.\r
-      * @param result        Result of the removal.\r
-      */\r
-     @Override\r
-     public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {\r
-         if (operation instanceof RemoveFileOperation) {\r
-             onRemoveFileOperationFinish((RemoveFileOperation)operation, result);\r
-                 \r
-         } else if (operation instanceof RenameFileOperation) {\r
-             onRenameFileOperationFinish((RenameFileOperation)operation, result);\r
-             \r
-         } else if (operation instanceof SynchronizeFileOperation) {\r
-             onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);\r
-             \r
-         } else if (operation instanceof CreateFolderOperation) {\r
-             onCreateFolderOperationFinish((CreateFolderOperation)operation, result);\r
-         }\r
-     }\r
\r
-     /**\r
-      * Updates the view associated to the activity after the finish of an operation trying create a new folder\r
-      * \r
-      * @param operation     Creation operation performed.\r
-      * @param result        Result of the creation.\r
-      */\r
-     private void onCreateFolderOperationFinish(CreateFolderOperation operation, RemoteOperationResult result) {\r
-         if (result.isSuccess()) {\r
-             dismissDialog(DIALOG_SHORT_WAIT);\r
-             mFileList.listDirectory();\r
-             \r
-         } else {\r
-             dismissDialog(DIALOG_SHORT_WAIT);\r
-             try {\r
-                 Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); \r
-                 msg.show();\r
-                     \r
-             } catch (NotFoundException e) {\r
-                 Log.e(TAG, "Error while trying to show fail message " , e);\r
-             }\r
-         }\r
-     }\r
\r
\r
-     /**\r
-      * Updates the view associated to the activity after the finish of an operation trying to remove a \r
-      * file. \r
-      * \r
-      * @param operation     Removal operation performed.\r
-      * @param result        Result of the removal.\r
-      */\r
-     private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {\r
-         dismissDialog(DIALOG_SHORT_WAIT);\r
-         if (result.isSuccess()) {\r
-             Toast msg = Toast.makeText(this, R.string.remove_success_msg, Toast.LENGTH_LONG);\r
-             msg.show();\r
-             OCFile removedFile = operation.getFile();\r
-             if (mDualPane) {\r
-                 FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
-                 if (details != null && removedFile.equals(details.getDisplayedFile()) ) {\r
-                     FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
-                     transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment\r
-                     transaction.commit();\r
-                 }\r
-             }\r
-             if (mStorageManager.getFileById(removedFile.getParentId()).equals(mCurrentDir)) {\r
-                 mFileList.listDirectory();\r
-             }\r
-                 \r
-         } else {\r
-             Toast msg = Toast.makeText(this, R.string.remove_fail_msg, Toast.LENGTH_LONG); \r
-             msg.show();\r
-             if (result.isSslRecoverableException()) {\r
-                 mLastSslUntrustedServerResult = result;\r
-                 showDialog(DIALOG_SSL_VALIDATOR); \r
-             }\r
-         }\r
-     }\r
\r
-     /**\r
-      * Updates the view associated to the activity after the finish of an operation trying to rename a \r
-      * file. \r
-      * \r
-      * @param operation     Renaming operation performed.\r
-      * @param result        Result of the renaming.\r
-      */\r
-     private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) {\r
-         dismissDialog(DIALOG_SHORT_WAIT);\r
-         OCFile renamedFile = operation.getFile();\r
-         if (result.isSuccess()) {\r
-             if (mDualPane) {\r
-                 FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
-                 if (details != null && renamedFile.equals(details.getDisplayedFile()) ) {\r
-                     details.updateFileDetails(renamedFile, AccountUtils.getCurrentOwnCloudAccount(this));\r
-                 }\r
-             }\r
-             if (mStorageManager.getFileById(renamedFile.getParentId()).equals(mCurrentDir)) {\r
-                 mFileList.listDirectory();\r
-             }\r
-             \r
-         } else {\r
-             if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {\r
-                 Toast msg = Toast.makeText(this, R.string.rename_local_fail_msg, Toast.LENGTH_LONG); \r
-                 msg.show();\r
-                 // TODO throw again the new rename dialog\r
-             } else {\r
-                 Toast msg = Toast.makeText(this, R.string.rename_server_fail_msg, Toast.LENGTH_LONG); \r
-                 msg.show();\r
-                 if (result.isSslRecoverableException()) {\r
-                     mLastSslUntrustedServerResult = result;\r
-                     showDialog(DIALOG_SSL_VALIDATOR); \r
-                 }\r
-             }\r
-         }\r
-     }\r
\r
\r
-     private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {\r
-         dismissDialog(DIALOG_SHORT_WAIT);\r
-         OCFile syncedFile = operation.getLocalFile();\r
-         if (!result.isSuccess()) {\r
-             if (result.getCode() == ResultCode.SYNC_CONFLICT) {\r
-                 Intent i = new Intent(this, ConflictsResolveActivity.class);\r
-                 i.putExtra(ConflictsResolveActivity.EXTRA_FILE, syncedFile);\r
-                 i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));\r
-                 startActivity(i);\r
-                 \r
-             } else {\r
-                 Toast msg = Toast.makeText(this, R.string.sync_file_fail_msg, Toast.LENGTH_LONG); \r
-                 msg.show();\r
-             }\r
-             \r
-         } else {\r
-             if (operation.transferWasRequested()) {\r
-                 mFileList.listDirectory();\r
-                 onTransferStateChanged(syncedFile, true, true);\r
-                 \r
-             } else {\r
-                 Toast msg = Toast.makeText(this, R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); \r
-                 msg.show();\r
-             }\r
-         }\r
-     }\r
\r
\r
-     /**\r
-      * {@inheritDoc}\r
-      */\r
-     @Override\r
-     public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) {\r
-         /*OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);\r
-         if (fileListFragment != null) { \r
-             fileListFragment.listDirectory();\r
-         }*/\r
-         if (mDualPane) {\r
-             FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
-             if (details != null && file.equals(details.getDisplayedFile()) ) {\r
-                 if (downloading || uploading) {\r
-                     details.updateFileDetails(file, AccountUtils.getCurrentOwnCloudAccount(this));\r
-                 } else {\r
-                     details.updateFileDetails(downloading || uploading);\r
-                 }\r
-             }\r
-         }\r
-     }\r
\r
\r
-     \r
\r
\r
- }\r
+ /* ownCloud Android client application
+  *   Copyright (C) 2011  Bartek Przybylski
+  *   Copyright (C) 2012-2013 ownCloud Inc.
+  *
+  *   This program is free software: you can redistribute it and/or modify
+  *   it under the terms of the GNU General Public License 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.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;
+ import android.content.ContentResolver;
+ import android.content.Context;
+ import android.content.DialogInterface;
+ import android.content.DialogInterface.OnClickListener;
+ 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;
+ import android.os.Bundle;
+ import android.os.Handler;
+ import android.os.IBinder;
+ 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;
+ import com.actionbarsherlock.app.ActionBar;
+ import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
+ import com.actionbarsherlock.app.SherlockFragmentActivity;
+ import com.actionbarsherlock.view.Menu;
+ import com.actionbarsherlock.view.MenuInflater;
+ import com.actionbarsherlock.view.MenuItem;
+ 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;
+ import com.owncloud.android.files.services.FileDownloader;
+ 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;
+ import com.owncloud.android.operations.RemoveFileOperation;
+ 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;
+ import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;
+ import com.owncloud.android.ui.fragment.FileDetailFragment;
+ import com.owncloud.android.ui.fragment.FileFragment;
+ import com.owncloud.android.ui.fragment.OCFileListFragment;
+ 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.
+  * 
+  * @author Bartek Przybylski
+  * @author David A. Velasco
+  */
+ public class FileDisplayActivity extends SherlockFragmentActivity implements
+     OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, OnRemoteOperationListener, EditNameDialogListener {
+     
+     private ArrayAdapter<String> mDirectories;
+     private OCFile mCurrentDir = null;
+     private OCFile mCurrentFile = null;
+     private DataStorageManager mStorageManager;
+     private SyncBroadcastReceiver mSyncBroadcastReceiver;
+     private UploadFinishReceiver mUploadFinishReceiver;
+     private DownloadFinishReceiver mDownloadFinishReceiver;
+     private FileDownloaderBinder mDownloaderBinder = null;
+     private FileUploaderBinder mUploaderBinder = null;
+     private ServiceConnection mDownloadConnection = null, mUploadConnection = null;
+     private RemoteOperationResult mLastSslUntrustedServerResult = null;
+     
+     private OCFileListFragment mFileList;
+     
+     private boolean mDualPane;
+     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;
+     
+     private static final String TAG = "FileDisplayActivity";
+     private OCFile mWaitingToPreview;
+     private Handler mHandler;
+     @Override
+     public void onCreate(Bundle savedInstanceState) {
+         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)) {
+             mCurrentDir = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); 
+         }
+         
+         /// Load of saved instance state: keep this always before initDataFromCurrentAccount()
+         if(savedInstanceState != null) {
+             // TODO - test if savedInstanceState should take precedence over file in the intent ALWAYS (now), NEVER. SOME TIMES
+             mCurrentDir = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE);
+             mWaitingToPreview = (OCFile) savedInstanceState.getParcelable(FileDetailActivity.KEY_WAITING_TO_PREVIEW);
+         } else {
+             mWaitingToPreview = null;
+         }
+         
+         if (!AccountUtils.accountsAreSetup(this)) {
+             /// no account available: FORCE ACCOUNT CREATION
+             mStorageManager = null;
+             createFirstAccount();
+             
+         } else {    /// at least an account is available
+             
+             initDataFromCurrentAccount();   // it checks mCurrentDir and mCurrentFile with the current account
+             
+         }
+         
+         mUploadConnection = new ListServiceConnection(); 
+         mDownloadConnection = new ListServiceConnection();
+         bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);
+         bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);
+         // PIN CODE request ;  best location is to decide, let's try this first
+         if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN) && savedInstanceState == null) {
+             requestPinCode();
+         }
+         // file observer
+         Intent observer_intent = new Intent(this, FileObserverService.class);
+         observer_intent.putExtra(FileObserverService.KEY_FILE_CMD, FileObserverService.CMD_INIT_OBSERVED_LIST);
+         startService(observer_intent);
+         
+             
+         /// USER INTERFACE
+         requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+             
+         // Drop-down navigation 
+         mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);
+         OCFile currFile = mCurrentDir;
+         while(mStorageManager != null && currFile != null && currFile.getFileName() != OCFile.PATH_SEPARATOR) {
+             mDirectories.add(currFile.getFileName());
+             currFile = mStorageManager.getFileById(currFile.getParentId());
+         }
+         mDirectories.add(OCFile.PATH_SEPARATOR);
+         // Inflate and set the layout view
+         setContentView(R.layout.files);    
+         mFileList = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
+         mDualPane = (findViewById(R.id.file_details_container) != null);
+         if (mDualPane) {
+             if (savedInstanceState == null) initFileDetailsInDualPane();
+         } else {
+             // quick patchES to fix problem in turn from landscape to portrait, when a file is selected in the right pane
+             // TODO serious refactorization in activities and fragments providing file browsing and handling 
+             if (mCurrentFile != null) {
+                 onFileClick(mCurrentFile);
+                 mCurrentFile = null;
+             }
+             Fragment rightPanel = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+             if (rightPanel != null) {
+                 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+                 transaction.remove(rightPanel);
+                 transaction.commit();
+             }
+         }
+             
+         // Action bar setup
+         ActionBar actionBar = getSupportActionBar();
+         actionBar.setHomeButtonEnabled(true);   // mandatory since Android ICS, according to the official documentation
+         actionBar.setDisplayHomeAsUpEnabled(mCurrentDir != null && mCurrentDir.getParentId() != 0);
+         actionBar.setDisplayShowTitleEnabled(false);
+         actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
+         actionBar.setListNavigationCallbacks(mDirectories, this);
+         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;
+     }
+     
+     /**
+      *  Load of state dependent of the existence of an ownCloud account
+      */
+     private void initDataFromCurrentAccount() {
+         /// Storage manager initialization - access to local database
+         mStorageManager = new FileDataStorageManager(
+                 AccountUtils.getCurrentOwnCloudAccount(this),
+                 getContentResolver());
+         /// Check if mCurrentDir is a directory
+         if(mCurrentDir != null && !mCurrentDir.isDirectory()) {
+             mCurrentFile = mCurrentDir;
+             mCurrentDir = mStorageManager.getFileById(mCurrentDir.getParentId());
+         }
+         
+         /// Check if mCurrentDir and mCurrentFile are in the current account, and update them
+         if (mCurrentDir != null) {
+             mCurrentDir = mStorageManager.getFileByPath(mCurrentDir.getRemotePath());   // mCurrentDir == null if it is not in the current account
+         }
+         if (mCurrentFile != null) {
+             if (mCurrentFile.fileExists()) {
+                 mCurrentFile = mStorageManager.getFileByPath(mCurrentFile.getRemotePath());   // mCurrentFile == null if it is not in the current account
+             }   // else : keep mCurrentFile with the received value; this is currently the case of an upload in progress, when the user presses the status notification in a landscape tablet
+         }
+         
+         /// Default to root if mCurrentDir was not found
+         if (mCurrentDir == null) {
+             mCurrentDir = mStorageManager.getFileByPath("/"); // will be NULL if the database was never synchronized
+         }
+     }
+         
+     
+     private void initFileDetailsInDualPane() {
+         if (mDualPane && getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG) == null) {
+             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+             if (mCurrentFile != null) {
+                 if (PreviewMediaFragment.canBePreviewed(mCurrentFile)) {
+                     if (mCurrentFile.isDown()) {
+                         transaction.replace(R.id.file_details_container, new PreviewMediaFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+                     } else {
+                         transaction.replace(R.id.file_details_container, new FileDetailFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+                         mWaitingToPreview = mCurrentFile;
+                     }
+                 } else {
+                     transaction.replace(R.id.file_details_container, new FileDetailFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+                 }
+                 mCurrentFile = null;
+                 
+             } else {
+                 transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment
+             }
+             transaction.commit();
+         }
+     }
+     
+     
+     @Override
+     public void onDestroy() {
+         super.onDestroy();
+         if (mDownloadConnection != null)
+             unbindService(mDownloadConnection);
+         if (mUploadConnection != null)
+             unbindService(mUploadConnection);
+     }
+     
+     @Override
+     public boolean onCreateOptionsMenu(Menu menu) {
+         MenuInflater inflater = getSherlock().getMenuInflater();
+             inflater.inflate(R.menu.main_menu, menu);
+             
+             return true;
+     }
+     @Override
+     public boolean onOptionsItemSelected(MenuItem item) {
+         boolean retval = true;
+         switch (item.getItemId()) {
+             case R.id.action_create_dir: {
+                 EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.uploader_info_dirname), "", -1, -1, this);
+                 dialog.show(getSupportFragmentManager(), "createdirdialog");
+                 break;
+             }
+             case R.id.action_sync_account: {
+                 startSynchronization();
+                 break;
+             }
+             case R.id.action_upload: {
+                 showDialog(DIALOG_CHOOSE_UPLOAD_SOURCE);
+                 break;
+             }
+             case R.id.action_settings: {
+                 Intent settingsIntent = new Intent(this, Preferences.class);
+                 startActivity(settingsIntent);
+                 break;
+             }
+             case android.R.id.home: {
+                 if(mCurrentDir != null && mCurrentDir.getParentId() != 0){
+                     onBackPressed(); 
+                 }
+                 break;
+             }
+             default:
+                 retval = super.onOptionsItemSelected(item);
+         }
+         return retval;
+     }
+     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);
+     }
+     @Override
+     public boolean onNavigationItemSelected(int itemPosition, long itemId) {
+         int i = itemPosition;
+         while (i-- != 0) {
+             onBackPressed();
+         }
+         // the next operation triggers a new call to this method, but it's necessary to 
+         // ensure that the name exposed in the action bar is the current directory when the 
+         // user selected it in the navigation list
+         if (itemPosition != 0)
+             getSupportActionBar().setSelectedNavigationItem(0);
+         return true;
+     }
+     /**
+      * Called, when the user selected something for uploading
+      */
+     public void onActivityResult(int requestCode, int resultCode, Intent data) {
+         
+         if (requestCode == ACTION_SELECT_CONTENT_FROM_APPS && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
+             requestSimpleUpload(data, resultCode);
+             
+         } else if (requestCode == ACTION_SELECT_MULTIPLE_FILES && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
+             requestMultipleUpload(data, resultCode);
+             
+         }
+     }
+     private void requestMultipleUpload(Intent data, int resultCode) {
+         String[] filePaths = data.getStringArrayExtra(UploadFilesActivity.EXTRA_CHOSEN_FILES);
+         if (filePaths != null) {
+             String[] remotePaths = new String[filePaths.length];
+             String remotePathBase = "";
+             for (int j = mDirectories.getCount() - 2; j >= 0; --j) {
+                 remotePathBase += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);
+             }
+             if (!remotePathBase.endsWith(OCFile.PATH_SEPARATOR))
+                 remotePathBase += OCFile.PATH_SEPARATOR;
+             for (int j = 0; j< remotePaths.length; j++) {
+                 remotePaths[j] = remotePathBase + (new File(filePaths[j])).getName();
+             }
+             Intent i = new Intent(this, FileUploader.class);
+             i.putExtra(FileUploader.KEY_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+             i.putExtra(FileUploader.KEY_LOCAL_FILE, filePaths);
+             i.putExtra(FileUploader.KEY_REMOTE_FILE, remotePaths);
+             i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
+             if (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)
+                 i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE);
+             startService(i);
+             
+         } else {
+             Log_OC.d("FileDisplay", "User clicked on 'Update' with no selection");
+             Toast t = Toast.makeText(this, getString(R.string.filedisplay_no_file_selected), Toast.LENGTH_LONG);
+             t.show();
+             return;
+         }
+     }
+     private void requestSimpleUpload(Intent data, int resultCode) {
+         String filepath = null;
+         try {
+             Uri selectedImageUri = data.getData();
+             String filemanagerstring = selectedImageUri.getPath();
+             String selectedImagePath = getPath(selectedImageUri);
+             if (selectedImagePath != null)
+                 filepath = selectedImagePath;
+             else
+                 filepath = filemanagerstring;
+             
+         } catch (Exception e) {
+             Log_OC.e("FileDisplay", "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e);
+             e.printStackTrace();
+             
+         } finally {
+             if (filepath == null) {
+                 Log_OC.e("FileDisplay", "Couldnt resolve path to file");
+                 Toast t = Toast.makeText(this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG);
+                 t.show();
+                 return;
+             }
+         }
+         Intent i = new Intent(this, FileUploader.class);
+         i.putExtra(FileUploader.KEY_ACCOUNT,
+                 AccountUtils.getCurrentOwnCloudAccount(this));
+         String remotepath = new String();
+         for (int j = mDirectories.getCount() - 2; j >= 0; --j) {
+             remotepath += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);
+         }
+         if (!remotepath.endsWith(OCFile.PATH_SEPARATOR))
+             remotepath += OCFile.PATH_SEPARATOR;
+         remotepath += new File(filepath).getName();
+         i.putExtra(FileUploader.KEY_LOCAL_FILE, filepath);
+         i.putExtra(FileUploader.KEY_REMOTE_FILE, remotepath);
+         i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
+         if (resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)
+             i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE);
+         startService(i);
+     }
+     @Override
+     public void onBackPressed() {
+         if (mDirectories.getCount() <= 1) {
+             finish();
+             return;
+         }
+         popDirname();
+         mFileList.onNavigateUp();
+         mCurrentDir = mFileList.getCurrentFile();
+         
+         if (mDualPane) {
+             // Resets the FileDetailsFragment on Tablets so that it always displays
+             Fragment fileFragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+             if (fileFragment != null && (fileFragment instanceof PreviewMediaFragment || !((FileDetailFragment) fileFragment).isEmpty())) {
+                 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+                 transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment                
+                 transaction.commit();
+             }
+         }
+         
+         if(mCurrentDir.getParentId() == 0){
+             ActionBar actionBar = getSupportActionBar(); 
+             actionBar.setDisplayHomeAsUpEnabled(false);
+         } 
+     }
+     @Override
+     protected void onSaveInstanceState(Bundle outState) {
+         // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved
+         Log_OC.d(getClass().toString(), "onSaveInstanceState() start");
+         super.onSaveInstanceState(outState);
+         outState.putParcelable(FileDetailFragment.EXTRA_FILE, mCurrentDir);
+         if (mDualPane) {
+             FileFragment fragment = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+             if (fragment != null) {
+                 OCFile file = fragment.getFile();
+                 if (file != null) {
+                     outState.putParcelable(FileDetailFragment.EXTRA_FILE, file);
+                 }
+             }
+         }
+         outState.putParcelable(FileDetailActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
+         Log_OC.d(getClass().toString(), "onSaveInstanceState() end");
+     }
 -
+     
+     @Override
+     protected void onResume() {
+         Log_OC.d(getClass().toString(), "onResume() start");
+         super.onResume();
+         if (AccountUtils.accountsAreSetup(this)) {
+             
+             if (mStorageManager == null) {
+                 // this is necessary for handling the come back to FileDisplayActivity when the first ownCloud account is created 
+                 initDataFromCurrentAccount();
+                 if (mDualPane) {
+                     initFileDetailsInDualPane();
+                 }
+                 mBackFromCreatingFirstAccount = true;
+             }
+             
+             // Listen for sync messages
+             IntentFilter syncIntentFilter = new IntentFilter(FileSyncService.SYNC_MESSAGE);
+             mSyncBroadcastReceiver = new SyncBroadcastReceiver();
+             registerReceiver(mSyncBroadcastReceiver, syncIntentFilter);
+             
+             // Listen for upload messages
+             IntentFilter uploadIntentFilter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);
+             mUploadFinishReceiver = new UploadFinishReceiver();
+             registerReceiver(mUploadFinishReceiver, uploadIntentFilter);
+             
+             // Listen for download messages
+             IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_ADDED_MESSAGE);
+             downloadIntentFilter.addAction(FileDownloader.DOWNLOAD_FINISH_MESSAGE);
+             mDownloadFinishReceiver = new DownloadFinishReceiver();
+             registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
+         
+             // List current directory
+             mFileList.listDirectory(mCurrentDir);   // TODO we should find the way to avoid the need of this (maybe it's not necessary yet; to check)
+             
+         } else {
+             
+             mStorageManager = null;     // an invalid object will be there if all the ownCloud accounts are removed
+             showDialog(DIALOG_SETUP_ACCOUNT);
+             
+         }
+         Log_OC.d(getClass().toString(), "onResume() end");
+     }
+     
+     @Override
+     protected void onPause() {
+         Log_OC.d(getClass().toString(), "onPause() start");
+         super.onPause();
+         if (mSyncBroadcastReceiver != null) {
+             unregisterReceiver(mSyncBroadcastReceiver);
+             mSyncBroadcastReceiver = null;
+         }
+         if (mUploadFinishReceiver != null) {
+             unregisterReceiver(mUploadFinishReceiver);
+             mUploadFinishReceiver = null;
+         }
+         if (mDownloadFinishReceiver != null) {
+             unregisterReceiver(mDownloadFinishReceiver);
+             mDownloadFinishReceiver = null;
+         }
+         if (!AccountUtils.accountsAreSetup(this)) {
+             dismissDialog(DIALOG_SETUP_ACCOUNT);
+         }
+         
+         Log_OC.d(getClass().toString(), "onPause() end");
+     }
+     
+     @Override
+     protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
+         if (id == DIALOG_SSL_VALIDATOR && mLastSslUntrustedServerResult != null) {
+             ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);
+         }
+     }
+     
+     @Override
+     protected Dialog onCreateDialog(int id) {
+         Dialog dialog = null;
+         AlertDialog.Builder builder;
+         switch (id) {
+         case DIALOG_SETUP_ACCOUNT: {
+             builder = new AlertDialog.Builder(this);
+             builder.setTitle(R.string.main_tit_accsetup);
+             builder.setMessage(R.string.main_wrn_accsetup);
+             builder.setCancelable(false);
+             builder.setPositiveButton(android.R.string.ok, new OnClickListener() {
+                 public void onClick(DialogInterface dialog, int which) {
+                     createFirstAccount();
+                     dialog.dismiss();
+                 }
+             });
+             String message = String.format(getString(R.string.common_exit), getString(R.string.app_name));
+             builder.setNegativeButton(message, new OnClickListener() {
+                 public void onClick(DialogInterface dialog, int which) {
+                     dialog.dismiss();
+                     finish();
+                 }
+             });
+             //builder.setNegativeButton(android.R.string.cancel, this);
+             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(
+                     R.string.wait_a_moment));
+             working_dialog.setIndeterminate(true);
+             working_dialog.setCancelable(false);
+             dialog = working_dialog;
+             break;
+         }
+         case DIALOG_CHOOSE_UPLOAD_SOURCE: {
+             
+             String[] items = null;
+             
+             String[] allTheItems = { getString(R.string.actionbar_upload_files),
+                                      getString(R.string.actionbar_upload_from_apps),
+                                      getString(R.string.actionbar_failed_instant_upload) };
+             
+             String[] commonItems = { getString(R.string.actionbar_upload_files),
+                                      getString(R.string.actionbar_upload_from_apps) };
+             
+             if (InstantUploadActivity.IS_ENABLED)
+                 items = allTheItems;
+             else 
+                 items = commonItems;
+             
+             builder = new AlertDialog.Builder(this);
+             builder.setTitle(R.string.actionbar_upload);
+             builder.setItems(items, new DialogInterface.OnClickListener() {
+                 public void onClick(DialogInterface dialog, int item) {
+                     if (item == 0) {
+                         // if (!mDualPane) {
+                         Intent action = new Intent(FileDisplayActivity.this, UploadFilesActivity.class);
+                         action.putExtra(UploadFilesActivity.EXTRA_ACCOUNT,
+                                 AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this));
+                         startActivityForResult(action, ACTION_SELECT_MULTIPLE_FILES);
+                         // } else {
+                         // TODO create and handle new fragment
+                         // LocalFileListFragment
+                         // }
+                     } else if (item == 1) {
+                         Intent action = new Intent(Intent.ACTION_GET_CONTENT);
+                         action = action.setType("*/*").addCategory(Intent.CATEGORY_OPENABLE);
+                         startActivityForResult(Intent.createChooser(action, getString(R.string.upload_chooser_title)),
+                                 ACTION_SELECT_CONTENT_FROM_APPS);
+                     } else if (item == 2 && InstantUploadActivity.IS_ENABLED) {
+                         Account account = AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this);
+                         Intent action = new Intent(FileDisplayActivity.this, InstantUploadActivity.class);
+                         action.putExtra(FileUploader.KEY_ACCOUNT, account);
+                         startActivity(action);
+                     }
+                 }
+             });
+             dialog = builder.create();
+             break;
+         }
+         case DIALOG_SSL_VALIDATOR: {
+             dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);
+             break;
+         }
+         case DIALOG_CERT_NOT_SAVED: {
+             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:
+             dialog = null;
+         }
+     
+         return dialog;
+     }
+     
+     /**
+      * Translates a content URI of an image to a physical path
+      * on the disk
+      * @param uri The URI to resolve
+      * @return The path to the image or null if it could not be found
+      */
+     public String getPath(Uri uri) {
+         String[] projection = { MediaStore.Images.Media.DATA };
+         Cursor cursor = managedQuery(uri, projection, null, null, null);
+         if (cursor != null) {
+             int column_index = cursor
+                     .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
+             cursor.moveToFirst();
+             return cursor.getString(column_index);
+         } 
+         return null;
+     }
+     
+     /**
+      * Pushes a directory to the drop down list
+      * @param directory to push
+      * @throws IllegalArgumentException If the {@link OCFile#isDirectory()} returns false.
+      */
+     public void pushDirname(OCFile directory) {
+         if(!directory.isDirectory()){
+             throw new IllegalArgumentException("Only directories may be pushed!");
+         }
+         mDirectories.insert(directory.getFileName(), 0);
+         mCurrentDir = directory;
+     }
+     /**
+      * Pops a directory name from the drop down list
+      * @return True, unless the stack is empty
+      */
+     public boolean popDirname() {
+         mDirectories.remove(mDirectories.getItem(0));
+         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> {
+     
+         public CustomArrayAdapter(FileDisplayActivity ctx, int view) {
+             super(ctx, view);
+         }
+     
+         public View getView(int position, View convertView, ViewGroup parent) {
+             View v = super.getView(position, convertView, parent);
+     
+             ((TextView) v).setTextColor(getResources().getColorStateList(
+                     android.R.color.white));
+             return v;
+         }
+     
+         public View getDropDownView(int position, View convertView,
+                 ViewGroup parent) {
+             View v = super.getDropDownView(position, convertView, parent);
+     
+             ((TextView) v).setTextColor(getResources().getColorStateList(
+                     android.R.color.white));
+     
+             return v;
+         }
+     
+     }
+     private class SyncBroadcastReceiver extends BroadcastReceiver {
+         /**
+          * {@link BroadcastReceiver} to enable syncing feedback in UI
+          */
+         @Override
+         public void onReceive(Context context, Intent intent) {
+             boolean inProgress = intent.getBooleanExtra(FileSyncService.IN_PROGRESS, false);
+             String accountName = intent.getStringExtra(FileSyncService.ACCOUNT_NAME);
+             Log_OC.d("FileDisplay", "sync of account " + accountName + " is in_progress: " + inProgress);
+             if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name)) {  
+             
+                 String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH); 
+                  
+                 boolean fillBlankRoot = false;
+                 if (mCurrentDir == null) {
+                     mCurrentDir = mStorageManager.getFileByPath("/");
+                     fillBlankRoot = (mCurrentDir != null);
+                 }
+                 if ((synchFolderRemotePath != null && mCurrentDir != null && (mCurrentDir.getRemotePath().equals(synchFolderRemotePath)))
+                         || fillBlankRoot ) {
+                     if (!fillBlankRoot) 
+                         mCurrentDir = getStorageManager().getFileByPath(synchFolderRemotePath);
+                     OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager()
+                             .findFragmentById(R.id.fileList);
+                     if (fileListFragment != null) {
+                         fileListFragment.listDirectory(mCurrentDir);
+                     }
+                 }
+                 
+                 setSupportProgressBarIndeterminateVisibility(inProgress);
+                 if (mBackFromCreatingFirstAccount) {
+                     // awful patch to fix problem with visibility of progress circle with the first refresh of the first account
+                     // TODO - kill this Activity when the first account has to be created instead of stack the account creation on it
+                     getSupportActionBar().hide();
+                     getSupportActionBar().show();
+                     mBackFromCreatingFirstAccount = false;
+                 }
+                 removeStickyBroadcast(intent);
+                 
+             }
+             
+             RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncService.SYNC_RESULT);
+             if (synchResult != null) {
+                 if (synchResult.getCode().equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) {
+                     mLastSslUntrustedServerResult = synchResult;
+                     showDialog(DIALOG_SSL_VALIDATOR); 
+                 }
+             }
+         }
+     }
+     
+     private class UploadFinishReceiver extends BroadcastReceiver {
+         /**
+          * Once the file upload has finished -> update view
+          *  @author David A. Velasco
+          * {@link BroadcastReceiver} to enable upload feedback in UI
+          */
+         @Override
+         public void onReceive(Context context, Intent intent) {
+             String uploadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
+             String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);
+             boolean sameAccount = accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name);
+             boolean isDescendant = (mCurrentDir != null) && (uploadedRemotePath != null) && (uploadedRemotePath.startsWith(mCurrentDir.getRemotePath()));
+             if (sameAccount && isDescendant) {
+                 OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
+                 if (fileListFragment != null) { 
+                     fileListFragment.listDirectory();
+                 }
+             }
+         }
+         
+     }
+     
+     
+     /**
+      * Class waiting for broadcast events from the {@link FielDownloader} service.
+      * 
+      * Updates the UI when a download is started or finished, provided that it is relevant for the
+      * current folder.
+      */
+     private class DownloadFinishReceiver extends BroadcastReceiver {
+         @Override
+         public void onReceive(Context context, Intent intent) {
+             boolean sameAccount = isSameAccount(context, intent);
+             String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
+             boolean isDescendant = isDescendant(downloadedRemotePath);
+             
+             if (sameAccount && isDescendant) {
+                 updateLeftPanel();
+                 if (mDualPane) {
+                     updateRightPanel(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false));
+                 }
+             }
+             
+             removeStickyBroadcast(intent);
+         }
+         private boolean isDescendant(String downloadedRemotePath) {
+             return (mCurrentDir != null && downloadedRemotePath != null && downloadedRemotePath.startsWith(mCurrentDir.getRemotePath()));
+         }
+         private boolean isSameAccount(Context context, Intent intent) {
+             String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
+             return (accountName != null && accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name));
+         }
+     }
+     
+     
+     protected void updateLeftPanel() {
+         OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
+         if (fileListFragment != null) { 
+             fileListFragment.listDirectory();
+         }
+     }
+     protected void updateRightPanel(String downloadEvent, String downloadedRemotePath, boolean success) {
+         Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+         boolean waitedPreview = (mWaitingToPreview != null && mWaitingToPreview.getRemotePath().equals(downloadedRemotePath));
+         if (fragment != null && fragment instanceof FileDetailFragment) {
+             FileDetailFragment detailsFragment = (FileDetailFragment) fragment;
+             OCFile fileInFragment = detailsFragment.getFile();
+             if (fileInFragment != null && !downloadedRemotePath.equals(fileInFragment.getRemotePath())) {
+                 // the user browsed to other file ; forget the automatic preview 
+                 mWaitingToPreview = null;
+                 
+             } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_ADDED_MESSAGE)) {
+                 // grant that the right panel updates the progress bar
+                 detailsFragment.listenForTransferProgress();
+                 detailsFragment.updateFileDetails(true, false);
+                 
+             } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_FINISH_MESSAGE)) {
+                 //  update the right panel 
+                 if (success && waitedPreview) {
+                     mWaitingToPreview = mStorageManager.getFileById(mWaitingToPreview.getFileId());   // update the file from database, for the local storage path
+                     FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+                     transaction.replace(R.id.file_details_container, new PreviewMediaFragment(mWaitingToPreview, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+                     transaction.commit();
+                     mWaitingToPreview = null;
+                     
+                 } else {
+                     detailsFragment.updateFileDetails(false, (success));
+                 }
+             }
+         }
+     }
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public DataStorageManager getStorageManager() {
+         return mStorageManager;
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onDirectoryClick(OCFile directory) {
+         pushDirname(directory);
+         ActionBar actionBar = getSupportActionBar();
+         actionBar.setDisplayHomeAsUpEnabled(true);
+         
+         if (mDualPane) {
+             // Resets the FileDetailsFragment on Tablets so that it always displays
+             Fragment fileFragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+             if (fileFragment != null && (fileFragment instanceof PreviewMediaFragment || !((FileDetailFragment) fileFragment).isEmpty())) {
+                 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+                 transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment                
+                 transaction.commit();
+             }
+         }
+     }
+     
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onFileClick(OCFile file) {
+         if (file != null && PreviewImageFragment.canBePreviewed(file)) {
+             // preview image - it handles the download, if needed
+             startPreviewImage(file);
+             
+         } else if (file != null && PreviewMediaFragment.canBePreviewed(file)) {
+             if (file.isDown()) {
+                 // general preview
+                 startMediaPreview(file);
+                 
+             } else {
+                 // automatic download, preview on finish
+                 startDownloadForPreview(file);
+                 
+             }
+         } else {
+             // details view
+             startDetails(file);
+         }
+     }
+     private void startPreviewImage(OCFile file) {
+         Intent showDetailsIntent = new Intent(this, PreviewImageActivity.class);
+         showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
+         showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+         startActivity(showDetailsIntent);
+     }
+     
+     private void startMediaPreview(OCFile file) {
+         if (mDualPane) {
+             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+             transaction.replace(R.id.file_details_container, new PreviewMediaFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+             transaction.commit();
+             
+         } else {
+             Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+             showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
+             showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+             startActivity(showDetailsIntent);
+         }
+     }
+     
+     private void startDownloadForPreview(OCFile file) {
+         if (mDualPane) {
+             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+             transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+             transaction.commit();
+             mWaitingToPreview = file;
+             requestForDownload();
+             
+         } else {
+             Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+             showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
+             showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+             startActivity(showDetailsIntent);
+         }
+     }
+     
+     private void startDetails(OCFile file) {
+         if (mDualPane && !file.isImage()) {
+             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+             transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+             transaction.commit();
+         } else {
+             Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+             showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
+             showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+             startActivity(showDetailsIntent);
+         }
+     }
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public OCFile getInitialDirectory() {
+         return mCurrentDir;
+     }
+     
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onFileStateChanged() {
+         OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
+         if (fileListFragment != null) { 
+             fileListFragment.listDirectory();
+         }
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public FileDownloaderBinder getFileDownloaderBinder() {
+         return mDownloaderBinder;
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public FileUploaderBinder getFileUploaderBinder() {
+         return mUploaderBinder;
+     }
+     
+     
+     /** Defines callbacks for service binding, passed to bindService() */
+     private class ListServiceConnection implements ServiceConnection {
+         @Override
+         public void onServiceConnected(ComponentName component, IBinder service) {
+             if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {
+                 Log_OC.d(TAG, "Download service connected");
+                 mDownloaderBinder = (FileDownloaderBinder) service;
+                 if (mWaitingToPreview != null) {
+                     requestForDownload();
+                 }
+                 
+             } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {
+                 Log_OC.d(TAG, "Upload service connected");
+                 mUploaderBinder = (FileUploaderBinder) service;
+             } else {
+                 return;
+             }
+             // a new chance to get the mDownloadBinder through getFileDownloadBinder() - THIS IS A MESS
+             if (mFileList != null)
+                 mFileList.listDirectory();
+             if (mDualPane) {
+                 Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+                 if (fragment != null && fragment instanceof FileDetailFragment) {
+                     FileDetailFragment detailFragment = (FileDetailFragment)fragment;
+                     detailFragment.listenForTransferProgress();
+                     detailFragment.updateFileDetails(false, false);
+                 }
+             }
+         }
+         @Override
+         public void onServiceDisconnected(ComponentName component) {
+             if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {
+                 Log_OC.d(TAG, "Download service disconnected");
+                 mDownloaderBinder = null;
+             } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {
+                 Log_OC.d(TAG, "Upload service disconnected");
+                 mUploaderBinder = null;
+             }
+         }
+     };    
+     
+     
+     /**
+      * Launch an intent to request the PIN code to the user before letting him use the app
+      */
+     private void requestPinCode() {
+         boolean pinStart = false;
+         SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+         pinStart = appPrefs.getBoolean("set_pincode", false);
+         if (pinStart) {
+             Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);
+             i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "FileDisplayActivity");
+             startActivity(i);
+         }
+     }
+     @Override
+     public void onSavedCertificate() {
+         startSynchronization();                
+     }
+     @Override
+     public void onFailedSavingCertificate() {
+         showDialog(DIALOG_CERT_NOT_SAVED);
+     }
+     /**
+      * Updates the view associated to the activity after the finish of some operation over files
+      * in the current account.
+      * 
+      * @param operation     Removal operation performed.
+      * @param result        Result of the removal.
+      */
+     @Override
+     public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+         if (operation instanceof RemoveFileOperation) {
+             onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
+                 
+         } else if (operation instanceof RenameFileOperation) {
+             onRenameFileOperationFinish((RenameFileOperation)operation, result);
+             
+         } else if (operation instanceof SynchronizeFileOperation) {
+             onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);
++
++        } else if (operation instanceof CreateFolderOperation) {
++            onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
+         }
+     }
+     /**
+      * Updates the view associated to the activity after the finish of an operation trying to remove a 
+      * file. 
+      * 
+      * @param operation     Removal operation performed.
+      * @param result        Result of the removal.
+      */
+     private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
+         dismissDialog(DIALOG_SHORT_WAIT);
+         if (result.isSuccess()) {
+             Toast msg = Toast.makeText(this, R.string.remove_success_msg, Toast.LENGTH_LONG);
+             msg.show();
+             OCFile removedFile = operation.getFile();
+             if (mDualPane) {
+                 FileFragment details = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+                 if (details != null && removedFile.equals(details.getFile())) {
+                     FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+                     transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment
+                     transaction.commit();
+                 }
+             }
+             if (mStorageManager.getFileById(removedFile.getParentId()).equals(mCurrentDir)) {
+                 mFileList.listDirectory();
+             }
+                 
+         } else {
+             Toast msg = Toast.makeText(this, R.string.remove_fail_msg, Toast.LENGTH_LONG); 
+             msg.show();
+             if (result.isSslRecoverableException()) {
+                 mLastSslUntrustedServerResult = result;
+                 showDialog(DIALOG_SSL_VALIDATOR); 
+             }
+         }
+     }
+     /**
++     * 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. 
+      * 
+      * @param operation     Renaming operation performed.
+      * @param result        Result of the renaming.
+      */
+     private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) {
+         dismissDialog(DIALOG_SHORT_WAIT);
+         OCFile renamedFile = operation.getFile();
+         if (result.isSuccess()) {
+             if (mDualPane) {
+                 FileFragment details = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+                 if (details != null && details instanceof FileDetailFragment && renamedFile.equals(details.getFile()) ) {
+                     ((FileDetailFragment) details).updateFileDetails(renamedFile, AccountUtils.getCurrentOwnCloudAccount(this));
+                 }
+             }
+             if (mStorageManager.getFileById(renamedFile.getParentId()).equals(mCurrentDir)) {
+                 mFileList.listDirectory();
+             }
+             
+         } else {
+             if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {
+                 Toast msg = Toast.makeText(this, R.string.rename_local_fail_msg, Toast.LENGTH_LONG); 
+                 msg.show();
+                 // TODO throw again the new rename dialog
+             } else {
+                 Toast msg = Toast.makeText(this, R.string.rename_server_fail_msg, Toast.LENGTH_LONG); 
+                 msg.show();
+                 if (result.isSslRecoverableException()) {
+                     mLastSslUntrustedServerResult = result;
+                     showDialog(DIALOG_SSL_VALIDATOR); 
+                 }
+             }
+         }
+     }
+     private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {
+         dismissDialog(DIALOG_SHORT_WAIT);
+         OCFile syncedFile = operation.getLocalFile();
+         if (!result.isSuccess()) {
+             if (result.getCode() == ResultCode.SYNC_CONFLICT) {
+                 Intent i = new Intent(this, ConflictsResolveActivity.class);
+                 i.putExtra(ConflictsResolveActivity.EXTRA_FILE, syncedFile);
+                 i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+                 startActivity(i);
+                 
+             } else {
+                 Toast msg = Toast.makeText(this, R.string.sync_file_fail_msg, Toast.LENGTH_LONG); 
+                 msg.show();
+             }
+             
+         } else {
+             if (operation.transferWasRequested()) {
+                 mFileList.listDirectory();
+                 onTransferStateChanged(syncedFile, true, true);
+                 
+             } else {
+                 Toast msg = Toast.makeText(this, R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); 
+                 msg.show();
+             }
+         }
+     }
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onTransferStateChanged(OCFile file, boolean downloading, boolean uploading) {
+         /*OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
+         if (fileListFragment != null) { 
+             fileListFragment.listDirectory();
+         }*/
+         if (mDualPane) {
+             FileFragment details = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+             if (details != null && details instanceof FileDetailFragment && file.equals(details.getFile()) ) {
+                 if (downloading || uploading) {
+                     ((FileDetailFragment)details).updateFileDetails(file, AccountUtils.getCurrentOwnCloudAccount(this));
+                 } else {
+                     ((FileDetailFragment)details).updateFileDetails(false, true);
+                 }
+             }
+         }
+     }
+     @Override
+     public void showFragmentWithDetails(OCFile file) {
+         if (mDualPane) {
+             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+             transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG); 
+             transaction.commit();
+             
+         } else {
+             Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+             showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
+             showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+             showDetailsIntent.putExtra(FileDetailActivity.EXTRA_MODE, FileDetailActivity.MODE_DETAILS);
+             startActivity(showDetailsIntent);
+         }
+     }
+     public void onDismiss(EditNameDialog dialog) {
+         //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) {
+                     // 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 += 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)) {
+             Intent i = new Intent(this, FileDownloader.class);
+             i.putExtra(FileDownloader.EXTRA_ACCOUNT, account);
+             i.putExtra(FileDownloader.EXTRA_FILE, mWaitingToPreview);
+             startService(i);
+         }
+     }
+     
+ }
index 0000000,8f34327..99b0b83
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,486 +1,475 @@@
 - *   it under the terms of the GNU General Public License as published by
 - *   the Free Software Foundation, either version 3 of the License.
+ /* ownCloud Android client application
+  *   Copyright (C) 2012-2013 ownCloud Inc.
+  *
+  *   This program is free software: you can redistribute it and/or modify
 -import android.util.Log;
++ *   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.util.ArrayList;
+ import java.util.List;
+ import android.accounts.Account;
+ import android.app.Activity;
+ import android.content.Intent;
+ import android.database.Cursor;
+ import android.graphics.Bitmap;
+ import android.graphics.BitmapFactory;
+ import android.os.Bundle;
 - * 
 - *         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/
+ import android.util.SparseArray;
+ import android.view.Gravity;
+ import android.view.View;
+ import android.view.View.OnClickListener;
+ import android.view.View.OnLongClickListener;
+ import android.view.ViewGroup;
+ import android.widget.Button;
+ import android.widget.CheckBox;
+ import android.widget.CompoundButton;
+ import android.widget.CompoundButton.OnCheckedChangeListener;
+ import android.widget.ImageButton;
+ import android.widget.LinearLayout;
+ import android.widget.TextView;
+ import android.widget.Toast;
+ import com.owncloud.android.AccountUtils;
+ import com.owncloud.android.Log_OC;
+ import com.owncloud.android.R;
+ import com.owncloud.android.db.DbHandler;
+ import com.owncloud.android.files.InstantUploadBroadcastReceiver;
+ import com.owncloud.android.files.services.FileUploader;
+ import com.owncloud.android.utils.FileStorageUtils;
+ /**
+  * This Activity is used to display a list with images they could not be
+  * uploaded instantly. The images can be selected for delete or for a try again
+  * upload
+  * 
+  * The entry-point for this activity is the 'Failed upload Notification" and a
+  * sub-menu underneath the 'Upload' menu-item
+  * 
+  * @author andomaex / Matthias Baumann
 -                Log.d(LOG_TAG, message);
+  */
+ public class InstantUploadActivity extends Activity {
+     private static final String LOG_TAG = InstantUploadActivity.class.getSimpleName();
+     private LinearLayout listView;
+     private static final String retry_chexbox_tag = "retry_chexbox_tag";
+     public static final boolean IS_ENABLED = false;
+     private static int MAX_LOAD_IMAGES = 5;
+     private int lastLoadImageIdx = 0;
+     private SparseArray<String> fileList = null;
+     CheckBox failed_upload_all_cb;
+     @Override
+     protected void onCreate(Bundle savedInstanceState) {
+         super.onCreate(savedInstanceState);
+         setContentView(R.layout.failed_upload_files);
+         Button delete_all_btn = (Button) findViewById(R.id.failed_upload_delete_all_btn);
+         delete_all_btn.setOnClickListener(getDeleteListner());
+         Button retry_all_btn = (Button) findViewById(R.id.failed_upload_retry_all_btn);
+         retry_all_btn.setOnClickListener(getRetryListner());
+         this.failed_upload_all_cb = (CheckBox) findViewById(R.id.failed_upload_headline_cb);
+         failed_upload_all_cb.setOnCheckedChangeListener(getCheckAllListener());
+         listView = (LinearLayout) findViewById(R.id.failed_upload_scrollviewlayout);
+         loadListView(true);
+     }
+     /**
+      * init the listview with ImageButtons, checkboxes and filename for every
+      * Image that was not successfully uploaded
+      * 
+      * this method is call at Activity creation and on delete one ore more
+      * list-entry an on retry the upload by clicking the ImageButton or by click
+      * to the 'retry all' button
+      * 
+      */
+     private void loadListView(boolean reset) {
+         DbHandler db = new DbHandler(getApplicationContext());
+         Cursor c = db.getFailedFiles();
+         if (reset) {
+             fileList = new SparseArray<String>();
+             listView.removeAllViews();
+             lastLoadImageIdx = 0;
+         }
+         if (c != null) {
+             try {
+                 c.moveToPosition(lastLoadImageIdx);
+                 while (c.moveToNext()) {
+                     lastLoadImageIdx++;
+                     String imp_path = c.getString(1);
+                     String message = c.getString(4);
+                     fileList.put(lastLoadImageIdx, imp_path);
+                     LinearLayout rowLayout = getHorizontalLinearLayout(lastLoadImageIdx);
+                     rowLayout.addView(getFileCheckbox(lastLoadImageIdx));
+                     rowLayout.addView(getImageButton(imp_path, lastLoadImageIdx));
+                     rowLayout.addView(getFileButton(imp_path, message, lastLoadImageIdx));
+                     listView.addView(rowLayout);
+                     Log_OC.d(LOG_TAG, imp_path + " on idx: " + lastLoadImageIdx);
+                     if (lastLoadImageIdx % MAX_LOAD_IMAGES == 0) {
+                         break;
+                     }
+                 }
+                 if (lastLoadImageIdx > 0) {
+                     addLoadMoreButton(listView);
+                 }
+             } finally {
+                 db.close();
+             }
+         }
+     }
+     private void addLoadMoreButton(LinearLayout listView) {
+         if (listView != null) {
+             Button loadmoreBtn = null;
+             View oldButton = listView.findViewById(42);
+             if (oldButton != null) {
+                 // remove existing button
+                 listView.removeView(oldButton);
+                 // to add the button at the end
+                 loadmoreBtn = (Button) oldButton;
+             } else {
+                 // create a new button to add to the scoll view
+                 loadmoreBtn = new Button(this);
+                 loadmoreBtn.setId(42);
+                 loadmoreBtn.setText(getString(R.string.failed_upload_load_more_images));
+                 loadmoreBtn.setBackgroundResource(R.color.owncloud_white);
+                 loadmoreBtn.setTextSize(12);
+                 loadmoreBtn.setOnClickListener(new OnClickListener() {
+                     @Override
+                     public void onClick(View v) {
+                         loadListView(false);
+                     }
+                 });
+             }
+             listView.addView(loadmoreBtn);
+         }
+     }
+     /**
+      * provide a list of CheckBox instances, looked up from parent listview this
+      * list ist used to select/deselect all checkboxes at the list
+      * 
+      * @return List<CheckBox>
+      */
+     private List<CheckBox> getCheckboxList() {
+         List<CheckBox> list = new ArrayList<CheckBox>();
+         for (int i = 0; i < listView.getChildCount(); i++) {
+             Log_OC.d(LOG_TAG, "ListView has Childs: " + listView.getChildCount());
+             View childView = listView.getChildAt(i);
+             if (childView != null && childView instanceof ViewGroup) {
+                 View checkboxView = getChildViews((ViewGroup) childView);
+                 if (checkboxView != null && checkboxView instanceof CheckBox) {
+                     Log_OC.d(LOG_TAG, "found Child: " + checkboxView.getId() + " " + checkboxView.getClass());
+                     list.add((CheckBox) checkboxView);
+                 }
+             }
+         }
+         return list;
+     }
+     /**
+      * recursive called method, used from getCheckboxList method
+      * 
+      * @param View
+      * @return View
+      */
+     private View getChildViews(ViewGroup view) {
+         if (view != null) {
+             for (int i = 0; i < view.getChildCount(); i++) {
+                 View cb = view.getChildAt(i);
+                 if (cb != null && cb instanceof ViewGroup) {
+                     return getChildViews((ViewGroup) cb);
+                 } else if (cb instanceof CheckBox) {
+                     return cb;
+                 }
+             }
+         }
+         return null;
+     }
+     /**
+      * create a new OnCheckedChangeListener for the 'check all' checkbox *
+      * 
+      * @return OnCheckedChangeListener to select all checkboxes at the list
+      */
+     private OnCheckedChangeListener getCheckAllListener() {
+         return new OnCheckedChangeListener() {
+             @Override
+             public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                 List<CheckBox> list = getCheckboxList();
+                 for (CheckBox checkbox : list) {
+                     ((CheckBox) checkbox).setChecked(isChecked);
+                 }
+             }
+         };
+     }
+     /**
+      * Button click Listener for the retry button at the headline
+      * 
+      * @return a Listener to perform a retry for all selected images
+      */
+     private OnClickListener getRetryListner() {
+         return new OnClickListener() {
+             @Override
+             public void onClick(View v) {
+                 try {
+                     List<CheckBox> list = getCheckboxList();
+                     for (CheckBox checkbox : list) {
+                         boolean to_retry = checkbox.isChecked();
+                         Log_OC.d(LOG_TAG, "Checkbox for " + checkbox.getId() + " was checked: " + to_retry);
+                         String img_path = fileList.get(checkbox.getId());
+                         if (to_retry) {
+                             final String msg = "Image-Path " + checkbox.getId() + " was checked: " + img_path;
+                             Log_OC.d(LOG_TAG, msg);
+                             startUpload(img_path);
+                         }
+                     }
+                 } finally {
+                     // refresh the List
+                     listView.removeAllViews();
+                     loadListView(true);
+                     if (failed_upload_all_cb != null) {
+                         failed_upload_all_cb.setChecked(false);
+                     }
+                 }
+             }
+         };
+     }
+     /**
+      * Button click Listener for the delete button at the headline
+      * 
+      * @return a Listener to perform a delete for all selected images
+      */
+     private OnClickListener getDeleteListner() {
+         return new OnClickListener() {
+             @Override
+             public void onClick(View v) {
+                 final DbHandler dbh = new DbHandler(getApplicationContext());
+                 try {
+                     List<CheckBox> list = getCheckboxList();
+                     for (CheckBox checkbox : list) {
+                         boolean to_be_delete = checkbox.isChecked();
+                         Log_OC.d(LOG_TAG, "Checkbox for " + checkbox.getId() + " was checked: " + to_be_delete);
+                         String img_path = fileList.get(checkbox.getId());
+                         Log_OC.d(LOG_TAG, "Image-Path " + checkbox.getId() + " was checked: " + img_path);
+                         if (to_be_delete) {
+                             boolean deleted = dbh.removeIUPendingFile(img_path);
+                             Log_OC.d(LOG_TAG, "removing " + checkbox.getId() + " was : " + deleted);
+                         }
+                     }
+                 } finally {
+                     dbh.close();
+                     // refresh the List
+                     listView.removeAllViews();
+                     loadListView(true);
+                     if (failed_upload_all_cb != null) {
+                         failed_upload_all_cb.setChecked(false);
+                     }
+                 }
+             }
+         };
+     }
+     private LinearLayout getHorizontalLinearLayout(int id) {
+         LinearLayout linearLayout = new LinearLayout(getApplicationContext());
+         linearLayout.setId(id);
+         linearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
+                 LinearLayout.LayoutParams.MATCH_PARENT));
+         linearLayout.setGravity(Gravity.RIGHT);
+         linearLayout.setOrientation(LinearLayout.HORIZONTAL);
+         return linearLayout;
+     }
+     private LinearLayout getVerticalLinearLayout() {
+         LinearLayout linearLayout = new LinearLayout(getApplicationContext());
+         linearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
+                 LinearLayout.LayoutParams.MATCH_PARENT));
+         linearLayout.setGravity(Gravity.TOP);
+         linearLayout.setOrientation(LinearLayout.VERTICAL);
+         return linearLayout;
+     }
+     private View getFileButton(final String img_path, String message, int id) {
+         TextView failureTextView = new TextView(this);
+         failureTextView.setText(getString(R.string.failed_upload_failure_text) + message);
+         failureTextView.setBackgroundResource(R.color.owncloud_white);
+         failureTextView.setTextSize(8);
+         failureTextView.setOnLongClickListener(getOnLongClickListener(message));
+         failureTextView.setPadding(5, 5, 5, 10);
+         TextView retryButton = new TextView(this);
+         retryButton.setId(id);
+         retryButton.setText(img_path);
+         retryButton.setBackgroundResource(R.color.owncloud_white);
+         retryButton.setTextSize(8);
+         retryButton.setOnClickListener(getImageButtonOnClickListener(img_path));
+         retryButton.setOnLongClickListener(getOnLongClickListener(message));
+         retryButton.setPadding(5, 5, 5, 10);
+         LinearLayout verticalLayout = getVerticalLinearLayout();
+         verticalLayout.addView(retryButton);
+         verticalLayout.addView(failureTextView);
+         return verticalLayout;
+     }
+     private OnLongClickListener getOnLongClickListener(final String message) {
+         return new OnLongClickListener() {
+             @Override
+             public boolean onLongClick(View v) {
++                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();
+                 return true;
+             }
+         };
+     }
+     private CheckBox getFileCheckbox(int id) {
+         CheckBox retryCB = new CheckBox(this);
+         retryCB.setId(id);
+         retryCB.setBackgroundResource(R.color.owncloud_white);
+         retryCB.setTextSize(8);
+         retryCB.setTag(retry_chexbox_tag);
+         return retryCB;
+     }
+     private ImageButton getImageButton(String img_path, int id) {
+         ImageButton imageButton = new ImageButton(this);
+         imageButton.setId(id);
+         imageButton.setClickable(true);
+         imageButton.setOnClickListener(getImageButtonOnClickListener(img_path));
+         // scale and add a thumbnail to the imagebutton
+         int base_scale_size = 32;
+         if (img_path != null) {
+             Log_OC.d(LOG_TAG, "add " + img_path + " to Image Button");
+             BitmapFactory.Options options = new BitmapFactory.Options();
+             options.inJustDecodeBounds = true;
+             Bitmap bitmap = BitmapFactory.decodeFile(img_path, options);
+             int width_tpm = options.outWidth, height_tmp = options.outHeight;
+             int scale = 3;
+             while (true) {
+                 if (width_tpm / 2 < base_scale_size || height_tmp / 2 < base_scale_size) {
+                     break;
+                 }
+                 width_tpm /= 2;
+                 height_tmp /= 2;
+                 scale++;
+             }
+             Log_OC.d(LOG_TAG, "scale Imgae with: " + scale);
+             BitmapFactory.Options options2 = new BitmapFactory.Options();
+             options2.inSampleSize = scale;
+             bitmap = BitmapFactory.decodeFile(img_path, options2);
+             if (bitmap != null) {
+                 Log_OC.d(LOG_TAG, "loaded Bitmap Bytes: " + bitmap.getRowBytes());
+                 imageButton.setImageBitmap(bitmap);
+             } else {
+                 Log_OC.d(LOG_TAG, "could not load imgage: " + img_path);
+             }
+         }
+         return imageButton;
+     }
+     private OnClickListener getImageButtonOnClickListener(final String img_path) {
+         return new OnClickListener() {
+             @Override
+             public void onClick(View v) {
+                 startUpload(img_path);
+                 loadListView(true);
+             }
+         };
+     }
+     /**
+      * start uploading a file to the INSTANT_UPLOD_DIR
+      * 
+      * @param img_path
+      */
+     private void startUpload(String img_path) {
+         // extract filename
+         String filename = FileStorageUtils.getInstantUploadFilePath(this, img_path);
+         if (canInstantUpload()) {
+             Account account = AccountUtils.getCurrentOwnCloudAccount(InstantUploadActivity.this);
+             // add file again to upload queue
+             DbHandler db = new DbHandler(InstantUploadActivity.this);
+             try {
+                 db.updateFileState(img_path, DbHandler.UPLOAD_STATUS_UPLOAD_LATER, null);
+             } finally {
+                 db.close();
+             }
+             Intent i = new Intent(InstantUploadActivity.this, FileUploader.class);
+             i.putExtra(FileUploader.KEY_ACCOUNT, account);
+             i.putExtra(FileUploader.KEY_LOCAL_FILE, img_path);
+             i.putExtra(FileUploader.KEY_REMOTE_FILE, filename);
+             i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
+             i.putExtra(com.owncloud.android.files.services.FileUploader.KEY_INSTANT_UPLOAD, true);
+             final String msg = "try to upload file with name :" + filename;
+             Log_OC.d(LOG_TAG, msg);
+             Toast toast = Toast.makeText(InstantUploadActivity.this, getString(R.string.failed_upload_retry_text)
+                     + filename, Toast.LENGTH_LONG);
+             toast.show();
+             startService(i);
+         } else {
+             Toast toast = Toast.makeText(InstantUploadActivity.this,
+                     getString(R.string.failed_upload_retry_do_nothing_text) + filename, Toast.LENGTH_LONG);
+             toast.show();
+         }
+     }
+     private boolean canInstantUpload() {
+         if (!InstantUploadBroadcastReceiver.isOnline(this)
+                 || (InstantUploadBroadcastReceiver.instantUploadViaWiFiOnly(this) && !InstantUploadBroadcastReceiver
+                         .isConnectedViaWiFi(this))) {
+             return false;
+         } else {
+             return true;
+         }
+     }
+ }
@@@ -26,7 -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;
@@@ -32,7 -31,7 +31,6 @@@ import javax.security.auth.x500.X500Pri
  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;
@@@ -23,9 -22,10 +22,9 @@@ 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;
  
  public class ConfirmationDialogFragment extends SherlockDialogFragment {
  
- /* ownCloud Android client application\r
-  *   Copyright (C) 2011  Bartek Przybylski\r
-  *   Copyright (C) 2012-2013 ownCloud Inc.\r
-  *\r
-  *   This program is free software: you can redistribute it and/or modify\r
-  *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 2 of the License, or\r
-  *   (at your option) any later version.\r
-  *\r
-  *   This program is distributed in the hope that it will be useful,\r
-  *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-  *   GNU General Public License for more details.\r
-  *\r
-  *   You should have received a copy of the GNU General Public License\r
-  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
-  *\r
-  */\r
- package com.owncloud.android.ui.fragment;\r
\r
- import java.io.File;\r
\r
- import org.apache.commons.httpclient.Credentials;\r
\r
- import android.accounts.Account;\r
- import android.accounts.AccountManager;\r
- import android.annotation.SuppressLint;\r
- import android.app.Activity;\r
- import android.content.ActivityNotFoundException;\r
- import android.content.BroadcastReceiver;\r
- import android.content.Context;\r
- import android.content.Intent;\r
- import android.content.IntentFilter;\r
- import android.graphics.Bitmap;\r
- import android.graphics.BitmapFactory;\r
- import android.graphics.BitmapFactory.Options;\r
- import android.graphics.Point;\r
- import android.net.Uri;\r
- import android.os.AsyncTask;\r
- import android.os.Bundle;\r
- import android.os.Handler;\r
- import android.support.v4.app.DialogFragment;\r
- import android.support.v4.app.FragmentTransaction;\r
- import android.util.Log;\r
- import android.view.Display;\r
- import android.view.LayoutInflater;\r
- import android.view.View;\r
- import android.view.View.OnClickListener;\r
- import android.view.ViewGroup;\r
- import android.webkit.MimeTypeMap;\r
- import android.widget.Button;\r
- import android.widget.CheckBox;\r
- import android.widget.ImageView;\r
- import android.widget.TextView;\r
- import android.widget.Toast;\r
\r
- import com.actionbarsherlock.app.SherlockFragment;\r
- import com.owncloud.android.DisplayUtils;\r
- import com.owncloud.android.authentication.AccountAuthenticator;\r
- import com.owncloud.android.datamodel.FileDataStorageManager;\r
- import com.owncloud.android.datamodel.OCFile;\r
- import com.owncloud.android.files.services.FileDownloader;\r
- import com.owncloud.android.files.services.FileObserverService;\r
- import com.owncloud.android.files.services.FileUploader;\r
- import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;\r
- import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;\r
- import com.owncloud.android.network.BearerCredentials;\r
- import com.owncloud.android.operations.OnRemoteOperationListener;\r
- import com.owncloud.android.operations.RemoteOperation;\r
- import com.owncloud.android.operations.RemoteOperationResult;\r
- import com.owncloud.android.operations.RemoteOperationResult.ResultCode;\r
- import com.owncloud.android.operations.RemoveFileOperation;\r
- import com.owncloud.android.operations.RenameFileOperation;\r
- import com.owncloud.android.operations.SynchronizeFileOperation;\r
- import com.owncloud.android.ui.activity.ConflictsResolveActivity;\r
- import com.owncloud.android.ui.activity.FileDetailActivity;\r
- import com.owncloud.android.ui.activity.FileDisplayActivity;\r
- import com.owncloud.android.ui.activity.TransferServiceGetter;\r
- import com.owncloud.android.ui.dialog.EditNameDialog;\r
- import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;\r
\r
- import com.owncloud.android.R;\r
- import eu.alefzero.webdav.WebdavUtils;\r
\r
- /**\r
-  * This Fragment is used to display the details about a file.\r
-  * \r
-  * @author Bartek Przybylski\r
-  * \r
-  */\r
- public class FileDetailFragment extends SherlockFragment implements\r
-         OnClickListener, ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener, EditNameDialogListener {\r
\r
-     public static final String EXTRA_FILE = "FILE";\r
-     public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
\r
-     private FileDetailFragment.ContainerActivity mContainerActivity;\r
-     \r
-     private int mLayout;\r
-     private View mView;\r
-     private OCFile mFile;\r
-     private Account mAccount;\r
-     private FileDataStorageManager mStorageManager;\r
-     private ImageView mPreview;\r
-     \r
-     private DownloadFinishReceiver mDownloadFinishReceiver;\r
-     private UploadFinishReceiver mUploadFinishReceiver;\r
-     \r
-     private Handler mHandler;\r
-     private RemoteOperation mLastRemoteOperation;\r
-     private DialogFragment mCurrentDialog;\r
\r
-     private static final String TAG = FileDetailFragment.class.getSimpleName();\r
-     public static final String FTAG = "FileDetails"; \r
-     public static final String FTAG_CONFIRMATION = "REMOVE_CONFIRMATION_FRAGMENT";\r
\r
-     \r
-     /**\r
-      * Creates an empty details fragment.\r
-      * \r
-      * It's necessary to keep a public constructor without parameters; the system uses it when tries to reinstantiate a fragment automatically. \r
-      */\r
-     public FileDetailFragment() {\r
-         mFile = null;\r
-         mAccount = null;\r
-         mStorageManager = null;\r
-         mLayout = R.layout.file_details_empty;\r
-     }\r
-     \r
-     \r
-     /**\r
-      * Creates a details fragment.\r
-      * \r
-      * When 'fileToDetail' or 'ocAccount' are null, creates a dummy layout (to use when a file wasn't tapped before).\r
-      * \r
-      * @param fileToDetail      An {@link OCFile} to show in the fragment\r
-      * @param ocAccount         An ownCloud account; needed to start downloads\r
-      */\r
-     public FileDetailFragment(OCFile fileToDetail, Account ocAccount) {\r
-         mFile = fileToDetail;\r
-         mAccount = ocAccount;\r
-         mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment \r
-         mLayout = R.layout.file_details_empty;\r
-     }\r
-     \r
-     \r
-     @Override\r
-     public void onCreate(Bundle savedInstanceState) {\r
-         super.onCreate(savedInstanceState);\r
-         mHandler = new Handler();\r
-     }\r
-     \r
\r
-     @Override\r
-     public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
-             Bundle savedInstanceState) {\r
-         super.onCreateView(inflater, container, savedInstanceState);\r
-         \r
-         if (savedInstanceState != null) {\r
-             mFile = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE);\r
-             mAccount = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_ACCOUNT);\r
-         }\r
-         \r
-         if(mFile != null && mAccount != null) {\r
-             mLayout = R.layout.file_details_fragment;\r
-         }\r
-         \r
-         View view = null;\r
-         view = inflater.inflate(mLayout, container, false);\r
-         mView = view;\r
-         \r
-         if (mLayout == R.layout.file_details_fragment) {\r
-             mView.findViewById(R.id.fdKeepInSync).setOnClickListener(this);\r
-             mView.findViewById(R.id.fdRenameBtn).setOnClickListener(this);\r
-             mView.findViewById(R.id.fdDownloadBtn).setOnClickListener(this);\r
-             mView.findViewById(R.id.fdOpenBtn).setOnClickListener(this);\r
-             mView.findViewById(R.id.fdRemoveBtn).setOnClickListener(this);\r
-             //mView.findViewById(R.id.fdShareBtn).setOnClickListener(this);\r
-             mPreview = (ImageView)mView.findViewById(R.id.fdPreview);\r
-         }\r
-         \r
-         updateFileDetails(false);\r
-         return view;\r
-     }\r
-     \r
\r
-     /**\r
-      * {@inheritDoc}\r
-      */\r
-     @Override\r
-     public void onAttach(Activity activity) {\r
-         super.onAttach(activity);\r
-         try {\r
-             mContainerActivity = (ContainerActivity) activity;\r
-         } catch (ClassCastException e) {\r
-             throw new ClassCastException(activity.toString() + " must implement " + FileDetailFragment.ContainerActivity.class.getSimpleName());\r
-         }\r
-     }\r
-     \r
-     \r
-     /**\r
-      * {@inheritDoc}\r
-      */\r
-     @Override\r
-     public void onActivityCreated(Bundle savedInstanceState) {\r
-         super.onActivityCreated(savedInstanceState);\r
-         if (mAccount != null) {\r
-             mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());;\r
-         }\r
-     }\r
-         \r
\r
-     @Override\r
-     public void onSaveInstanceState(Bundle outState) {\r
-         Log.i(getClass().toString(), "onSaveInstanceState() start");\r
-         super.onSaveInstanceState(outState);\r
-         outState.putParcelable(FileDetailFragment.EXTRA_FILE, mFile);\r
-         outState.putParcelable(FileDetailFragment.EXTRA_ACCOUNT, mAccount);\r
-         Log.i(getClass().toString(), "onSaveInstanceState() end");\r
-     }\r
\r
-     \r
-     @Override\r
-     public void onResume() {\r
-         super.onResume();\r
-         \r
-         mDownloadFinishReceiver = new DownloadFinishReceiver();\r
-         IntentFilter filter = new IntentFilter(\r
-                 FileDownloader.DOWNLOAD_FINISH_MESSAGE);\r
-         getActivity().registerReceiver(mDownloadFinishReceiver, filter);\r
-         \r
-         mUploadFinishReceiver = new UploadFinishReceiver();\r
-         filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);\r
-         getActivity().registerReceiver(mUploadFinishReceiver, filter);\r
-         \r
-         mPreview = (ImageView)mView.findViewById(R.id.fdPreview);\r
-     }\r
\r
-     @Override\r
-     public void onPause() {\r
-         super.onPause();\r
-         \r
-         getActivity().unregisterReceiver(mDownloadFinishReceiver);\r
-         mDownloadFinishReceiver = null;\r
-         \r
-         getActivity().unregisterReceiver(mUploadFinishReceiver);\r
-         mUploadFinishReceiver = null;\r
-         \r
-         if (mPreview != null) {\r
-             mPreview = null;\r
-         }\r
-     }\r
\r
+ /* ownCloud Android client application
+  *   Copyright (C) 2011  Bartek Przybylski
+  *   Copyright (C) 2012-2013 ownCloud Inc.
+  *
+  *   This program is free software: you can redistribute it and/or modify
+  *   it under the terms of the GNU General Public License 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.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;
+ import android.content.Context;
+ import android.content.Intent;
+ import android.content.IntentFilter;
+ 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;
+ import android.view.ViewGroup;
+ import android.webkit.MimeTypeMap;
+ import android.widget.Button;
+ import android.widget.CheckBox;
+ import android.widget.ImageView;
+ 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;
+ import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
+ import com.owncloud.android.operations.RemoveFileOperation;
+ import com.owncloud.android.operations.RenameFileOperation;
+ import com.owncloud.android.operations.SynchronizeFileOperation;
+ import com.owncloud.android.ui.activity.ConflictsResolveActivity;
+ 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.
+  * 
+  * @author Bartek Przybylski
+  * @author David A. Velasco
+  */
+ public class FileDetailFragment extends SherlockFragment implements
+         OnClickListener, 
+         ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener, EditNameDialogListener,
+         FileFragment {
+     public static final String EXTRA_FILE = "FILE";
+     public static final String EXTRA_ACCOUNT = "ACCOUNT";
+     private FileFragment.ContainerActivity mContainerActivity;
+     
+     private int mLayout;
+     private View mView;
+     private OCFile mFile;
+     private Account mAccount;
+     private FileDataStorageManager mStorageManager;
+     
+     private UploadFinishReceiver mUploadFinishReceiver;
+     public ProgressListener mProgressListener;
+     
+     private Handler mHandler;
+     private RemoteOperation mLastRemoteOperation;
+     
+     private static final String TAG = FileDetailFragment.class.getSimpleName();
+     public static final String FTAG = "FileDetails"; 
+     public static final String FTAG_CONFIRMATION = "REMOVE_CONFIRMATION_FRAGMENT";
+     
+     /**
+      * Creates an empty details fragment.
+      * 
+      * It's necessary to keep a public constructor without parameters; the system uses it when tries to reinstantiate a fragment automatically. 
+      */
+     public FileDetailFragment() {
+         mFile = null;
+         mAccount = null;
+         mStorageManager = null;
+         mLayout = R.layout.file_details_empty;
+         mProgressListener = null;
+     }
+     
 -    
+     /**
+      * Creates a details fragment.
+      * 
+      * When 'fileToDetail' or 'ocAccount' are null, creates a dummy layout (to use when a file wasn't tapped before).
+      * 
+      * @param fileToDetail      An {@link OCFile} to show in the fragment
+      * @param ocAccount         An ownCloud account; needed to start downloads
+      */
+     public FileDetailFragment(OCFile fileToDetail, Account ocAccount) {
+         mFile = fileToDetail;
+         mAccount = ocAccount;
+         mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment 
+         mLayout = R.layout.file_details_empty;
+         mProgressListener = null;
+     }
+     
+     
+     @Override
+     public void onCreate(Bundle savedInstanceState) {
+         super.onCreate(savedInstanceState);
+         mHandler = new Handler();
+     }
+     
+     @Override
+     public View onCreateView(LayoutInflater inflater, ViewGroup container,
+             Bundle savedInstanceState) {
+         super.onCreateView(inflater, container, savedInstanceState);
+         
+         if (savedInstanceState != null) {
+             mFile = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE);
+             mAccount = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_ACCOUNT);
+         }
+         
+         if(mFile != null && mAccount != null) {
+             mLayout = R.layout.file_details_fragment;
+         }
+         
+         View view = null;
+         view = inflater.inflate(mLayout, container, false);
+         mView = view;
+         
+         if (mLayout == R.layout.file_details_fragment) {
+             mView.findViewById(R.id.fdKeepInSync).setOnClickListener(this);
+             mView.findViewById(R.id.fdRenameBtn).setOnClickListener(this);
+             mView.findViewById(R.id.fdDownloadBtn).setOnClickListener(this);
+             mView.findViewById(R.id.fdOpenBtn).setOnClickListener(this);
+             mView.findViewById(R.id.fdRemoveBtn).setOnClickListener(this);
+             //mView.findViewById(R.id.fdShareBtn).setOnClickListener(this);
+             ProgressBar progressBar = (ProgressBar)mView.findViewById(R.id.fdProgressBar);
+             mProgressListener = new ProgressListener(progressBar);
+         }
+         
+         updateFileDetails(false, false);
+         return view;
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onAttach(Activity activity) {
+         super.onAttach(activity);
+         try {
+             mContainerActivity = (ContainerActivity) activity;
+             
+         } catch (ClassCastException e) {
+             throw new ClassCastException(activity.toString() + " must implement " + FileDetailFragment.ContainerActivity.class.getSimpleName());
+         }
+     }
+     
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onActivityCreated(Bundle savedInstanceState) {
+         super.onActivityCreated(savedInstanceState);
+         if (mAccount != null) {
+             mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());
+         }
+     }
+         
+     @Override
+     public void onSaveInstanceState(Bundle outState) {
+         super.onSaveInstanceState(outState);
+         outState.putParcelable(FileDetailFragment.EXTRA_FILE, mFile);
+         outState.putParcelable(FileDetailFragment.EXTRA_ACCOUNT, mAccount);
+     }
+     @Override
+     public void onStart() {
+         super.onStart();
+         listenForTransferProgress();
+     }
+     
+     @Override
+     public void onResume() {
+         super.onResume();
+         mUploadFinishReceiver = new UploadFinishReceiver();
+         IntentFilter filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);
+         getActivity().registerReceiver(mUploadFinishReceiver, filter);
+     }
+     @Override
+     public void onPause() {
+         super.onPause();
+         if (mUploadFinishReceiver != null) {
+             getActivity().unregisterReceiver(mUploadFinishReceiver);
+             mUploadFinishReceiver = null;
+         }
+     }
+     
+     @Override
+     public void onStop() {
+         super.onStop();
+         leaveTransferProgress();
+     }
+     
 -    @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\r
 +    public View getView() {\r
 +        return super.getView() == null ? mView : super.getView();\r
 +    }\r
\r
-     \r
++
 +    \r
 +    @Override\r
 +    public void onClick(View v) {\r
 +        switch (v.getId()) {\r
 +            case R.id.fdDownloadBtn: {\r
 +                FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();\r
 +                FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();\r
 +                if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {\r
 +                    downloaderBinder.cancel(mAccount, mFile);\r
 +                    if (mFile.isDown()) {\r
 +                        setButtonsForDown();\r
 +                    } else {\r
 +                        setButtonsForRemote();\r
 +                    }\r
 +\r
 +                } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile)) {\r
 +                    uploaderBinder.cancel(mAccount, mFile);\r
 +                    if (!mFile.fileExists()) {\r
 +                        // TODO make something better\r
 +                        if (getActivity() instanceof FileDisplayActivity) {\r
 +                            // double pane\r
 +                            FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();\r
 +                            transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FTAG); // empty FileDetailFragment\r
 +                            transaction.commit();\r
 +                            mContainerActivity.onFileStateChanged();\r
 +                        } else {\r
 +                            getActivity().finish();\r
 +                        }\r
 +                        \r
 +                    } else if (mFile.isDown()) {\r
 +                        setButtonsForDown();\r
 +                    } else {\r
 +                        setButtonsForRemote();\r
 +                    }\r
 +                    \r
 +                } else {\r
 +                    mLastRemoteOperation = new SynchronizeFileOperation(mFile, null, mStorageManager, mAccount, true, false, getActivity());\r
 +                    mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());\r
 +                \r
 +                    // update ui \r
 +                    boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
 +                    getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
 +                    setButtonsForTransferring(); // disable button immediately, although the synchronization does not result in a file transference\r
 +                    \r
 +                }\r
 +                break;\r
 +            }\r
-             case R.id.fdKeepInSync: {\r
-                 CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync);\r
-                 mFile.setKeepInSync(cb.isChecked());\r
-                 mStorageManager.saveFile(mFile);\r
-                 \r
-                 /// register the OCFile instance in the observer service to monitor local updates;\r
-                 /// if necessary, the file is download \r
-                 Intent intent = new Intent(getActivity().getApplicationContext(),\r
-                                            FileObserverService.class);\r
-                 intent.putExtra(FileObserverService.KEY_FILE_CMD,\r
-                            (cb.isChecked()?\r
-                                    FileObserverService.CMD_ADD_OBSERVED_FILE:\r
-                                    FileObserverService.CMD_DEL_OBSERVED_FILE));\r
-                 intent.putExtra(FileObserverService.KEY_CMD_ARG_FILE, mFile);\r
-                 intent.putExtra(FileObserverService.KEY_CMD_ARG_ACCOUNT, mAccount);\r
-                 Log.e(TAG, "starting observer service");\r
-                 getActivity().startService(intent);\r
-                 \r
-                 if (mFile.keepInSync()) {\r
-                     onClick(getView().findViewById(R.id.fdDownloadBtn));    // force an immediate synchronization\r
-                 }\r
-                 break;\r
-             }\r
-             case R.id.fdRenameBtn: {\r
-                 EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), mFile.getFileName(), this);\r
-                 dialog.show(getFragmentManager(), "nameeditdialog");\r
-                 break;\r
-             }   \r
-             case R.id.fdRemoveBtn: {\r
-                 ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(\r
-                         R.string.confirmation_remove_alert,\r
-                         new String[]{mFile.getFileName()},\r
-                         mFile.isDown() ? R.string.confirmation_remove_remote_and_local : R.string.confirmation_remove_remote,\r
-                         mFile.isDown() ? R.string.confirmation_remove_local : -1,\r
-                         R.string.common_cancel);\r
-                 confDialog.setOnConfirmationListener(this);\r
-                 mCurrentDialog = confDialog;\r
-                 mCurrentDialog.show(getFragmentManager(), FTAG_CONFIRMATION);\r
-                 break;\r
-             }\r
-             case R.id.fdOpenBtn: {\r
-                 String storagePath = mFile.getStoragePath();\r
-                 String encodedStoragePath = WebdavUtils.encodePath(storagePath);\r
-                 try {\r
-                     Intent i = new Intent(Intent.ACTION_VIEW);\r
-                     i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype());\r
-                     i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\r
-                     startActivity(i);\r
-                     \r
-                 } catch (Throwable t) {\r
-                     Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());\r
-                     boolean toastIt = true; \r
-                     String mimeType = "";\r
-                     try {\r
-                         Intent i = new Intent(Intent.ACTION_VIEW);\r
-                         mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));\r
-                         if (mimeType == null || !mimeType.equals(mFile.getMimetype())) {\r
-                             if (mimeType != null) {\r
-                                 i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);\r
-                             } else {\r
-                                 // desperate try\r
-                                 i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*/*");\r
-                             }\r
-                             i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\r
-                             startActivity(i);\r
-                             toastIt = false;\r
-                         }\r
-                         \r
-                     } catch (IndexOutOfBoundsException e) {\r
-                         Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);\r
-                         \r
-                     } catch (ActivityNotFoundException e) {\r
-                         Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");\r
-                         \r
-                     } catch (Throwable th) {\r
-                         Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);\r
-                         \r
-                     } finally {\r
-                         if (toastIt) {\r
-                             Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();\r
-                         }\r
-                     }\r
-                     \r
-                 }\r
-                 break;\r
-             }\r
-             default:\r
-                 Log.e(TAG, "Incorrect view clicked!");\r
-         }\r
-         \r
-         /* else if (v.getId() == R.id.fdShareBtn) {\r
-             Thread t = new Thread(new ShareRunnable(mFile.getRemotePath()));\r
-             t.start();\r
-         }*/\r
-     }\r
-     \r
-     \r
-     @Override\r
-     public void onConfirmation(String callerTag) {\r
-         if (callerTag.equals(FTAG_CONFIRMATION)) {\r
-             if (mStorageManager.getFileById(mFile.getFileId()) != null) {\r
-                 mLastRemoteOperation = new RemoveFileOperation( mFile, \r
-                                                                 true, \r
-                                                                 mStorageManager);\r
-                 mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());\r
-                 boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
-                 getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
-             }\r
-         }\r
-         mCurrentDialog.dismiss();\r
-         mCurrentDialog = null;\r
-     }\r
-     \r
-     @Override\r
-     public void onNeutral(String callerTag) {\r
-         File f = null;\r
-         if (mFile.isDown() && (f = new File(mFile.getStoragePath())).exists()) {\r
-             f.delete();\r
-             mFile.setStoragePath(null);\r
-             mStorageManager.saveFile(mFile);\r
-             updateFileDetails(mFile, mAccount);\r
-         }\r
-         mCurrentDialog.dismiss();\r
-         mCurrentDialog = null;\r
-     }\r
-     \r
-     @Override\r
-     public void onCancel(String callerTag) {\r
-         Log.d(TAG, "REMOVAL CANCELED");\r
-         mCurrentDialog.dismiss();\r
-         mCurrentDialog = null;\r
-     }\r
-     \r
-     \r
-     /**\r
-      * Check if the fragment was created with an empty layout. An empty fragment can't show file details, must be replaced.\r
-      * \r
-      * @return  True when the fragment was created with the empty layout.\r
-      */\r
-     public boolean isEmpty() {\r
-         return (mLayout == R.layout.file_details_empty || mFile == null || mAccount == null);\r
-     }\r
\r
-     \r
-     /**\r
-      * Can be used to get the file that is currently being displayed.\r
-      * @return The file on the screen.\r
-      */\r
-     public OCFile getDisplayedFile(){\r
-         return mFile;\r
-     }\r
-     \r
-     /**\r
-      * Use this method to signal this Activity that it shall update its view.\r
-      * \r
-      * @param file : An {@link OCFile}\r
-      */\r
-     public void updateFileDetails(OCFile file, Account ocAccount) {\r
-         mFile = file;\r
-         if (ocAccount != null && ( \r
-                 mStorageManager == null || \r
-                 (mAccount != null && !mAccount.equals(ocAccount))\r
-            )) {\r
-             mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());\r
-         }\r
-         mAccount = ocAccount;\r
-         updateFileDetails(false);\r
-     }\r
-     \r
\r
-     /**\r
-      * Updates the view with all relevant details about that file.\r
-      *\r
-      * TODO Remove parameter when the transferring state of files is kept in database. \r
-      * \r
-      * @param transferring      Flag signaling if the file should be considered as downloading or uploading, \r
-      *                          although {@link FileDownloaderBinder#isDownloading(Account, OCFile)}  and \r
-      *                          {@link FileUploaderBinder#isUploading(Account, OCFile)} return false.\r
-      * \r
-      */\r
-     public void updateFileDetails(boolean transferring) {\r
\r
-         if (mFile != null && mAccount != null && mLayout == R.layout.file_details_fragment) {\r
-             \r
-             // set file details\r
-             setFilename(mFile.getFileName());\r
-             setFiletype(mFile.getMimetype());\r
-             setFilesize(mFile.getFileLength());\r
-             if(ocVersionSupportsTimeCreated()){\r
-                 setTimeCreated(mFile.getCreationTimestamp());\r
-             }\r
-            \r
-             setTimeModified(mFile.getModificationTimestamp());\r
-             \r
-             CheckBox cb = (CheckBox)getView().findViewById(R.id.fdKeepInSync);\r
-             cb.setChecked(mFile.keepInSync());\r
\r
-             // configure UI for depending upon local state of the file\r
-             //if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath()) || FileUploader.isUploading(mAccount, mFile.getRemotePath())) {\r
-             FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();\r
-             FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();\r
-             if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) || (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile))) {\r
-                 setButtonsForTransferring();\r
-                 \r
-             } else if (mFile.isDown()) {\r
-                 // Update preview\r
-                 if (mFile.getMimetype().startsWith("image/")) {\r
-                     BitmapLoader bl = new BitmapLoader();\r
-                     bl.execute(new String[]{mFile.getStoragePath()});\r
-                 }\r
-                 \r
-                 setButtonsForDown();\r
-                 \r
-             } else {\r
-                 // TODO load default preview image; when the local file is removed, the preview remains there\r
-                 setButtonsForRemote();\r
-             }\r
-         }\r
-         getView().invalidate();\r
-     }\r
-     \r
-     \r
-     /**\r
-      * Updates the filename in view\r
-      * @param filename to set\r
-      */\r
-     private void setFilename(String filename) {\r
-         TextView tv = (TextView) getView().findViewById(R.id.fdFilename);\r
-         if (tv != null)\r
-             tv.setText(filename);\r
-     }\r
\r
-     /**\r
-      * Updates the MIME type in view\r
-      * @param mimetype to set\r
-      */\r
-     private void setFiletype(String mimetype) {\r
-         TextView tv = (TextView) getView().findViewById(R.id.fdType);\r
-         if (tv != null) {\r
-             String printableMimetype = DisplayUtils.convertMIMEtoPrettyPrint(mimetype);;        \r
-             tv.setText(printableMimetype);\r
-         }\r
-         ImageView iv = (ImageView) getView().findViewById(R.id.fdIcon);\r
-         if (iv != null) {\r
-             iv.setImageResource(DisplayUtils.getResourceId(mimetype));\r
-         }\r
-     }\r
\r
-     /**\r
-      * Updates the file size in view\r
-      * @param filesize in bytes to set\r
-      */\r
-     private void setFilesize(long filesize) {\r
-         TextView tv = (TextView) getView().findViewById(R.id.fdSize);\r
-         if (tv != null)\r
-             tv.setText(DisplayUtils.bytesToHumanReadable(filesize));\r
-     }\r
-     \r
-     /**\r
-      * Updates the time that the file was created in view\r
-      * @param milliseconds Unix time to set\r
-      */\r
-     private void setTimeCreated(long milliseconds){\r
-         TextView tv = (TextView) getView().findViewById(R.id.fdCreated);\r
-         TextView tvLabel = (TextView) getView().findViewById(R.id.fdCreatedLabel);\r
-         if(tv != null){\r
-             tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));\r
-             tv.setVisibility(View.VISIBLE);\r
-             tvLabel.setVisibility(View.VISIBLE);\r
-         }\r
-     }\r
-     \r
-     /**\r
-      * Updates the time that the file was last modified\r
-      * @param milliseconds Unix time to set\r
-      */\r
-     private void setTimeModified(long milliseconds){\r
-         TextView tv = (TextView) getView().findViewById(R.id.fdModified);\r
-         if(tv != null){\r
-             tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));\r
-         }\r
-     }\r
-     \r
-     /**\r
-      * Enables or disables buttons for a file being downloaded\r
-      */\r
-     private void setButtonsForTransferring() {\r
-         if (!isEmpty()) {\r
-             Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
-             downloadButton.setText(R.string.common_cancel);\r
-             //downloadButton.setEnabled(false);\r
-         \r
-             // let's protect the user from himself ;)\r
-             ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false);\r
-             ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(false);\r
-             ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(false);\r
-             getView().findViewById(R.id.fdKeepInSync).setEnabled(false);\r
-         }\r
-     }\r
-     \r
-     /**\r
-      * Enables or disables buttons for a file locally available \r
-      */\r
-     private void setButtonsForDown() {\r
-         if (!isEmpty()) {\r
-             Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
-             downloadButton.setText(R.string.filedetails_sync_file);\r
-         \r
-             ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(true);\r
-             ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);\r
-             ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true);\r
-             getView().findViewById(R.id.fdKeepInSync).setEnabled(true);\r
-         }\r
-     }\r
\r
-     /**\r
-      * Enables or disables buttons for a file not locally available \r
-      */\r
-     private void setButtonsForRemote() {\r
-         if (!isEmpty()) {\r
-             Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
-             downloadButton.setText(R.string.filedetails_download);\r
-             \r
-             ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false);\r
-             ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);\r
-             ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true);\r
-             getView().findViewById(R.id.fdKeepInSync).setEnabled(true);\r
-         }\r
-     }\r
-     \r
\r
-     /**\r
-      * In ownCloud 3.X.X and 4.X.X there is a bug that SabreDAV does not return\r
-      * the time that the file was created. There is a chance that this will\r
-      * be fixed in future versions. Use this method to check if this version of\r
-      * ownCloud has this fix.\r
-      * @return True, if ownCloud the ownCloud version is supporting creation time\r
-      */\r
-     private boolean ocVersionSupportsTimeCreated(){\r
-         /*if(mAccount != null){\r
-             AccountManager accManager = (AccountManager) getActivity().getSystemService(Context.ACCOUNT_SERVICE);\r
-             OwnCloudVersion ocVersion = new OwnCloudVersion(accManager\r
-                     .getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION));\r
-             if(ocVersion.compareTo(new OwnCloudVersion(0x030000)) < 0) {\r
-                 return true;\r
-             }\r
-         }*/\r
-         return false;\r
-     }\r
-     \r
-     \r
-     /**\r
-      * Interface to implement by any Activity that includes some instance of FileDetailFragment\r
-      * \r
-      * @author David A. Velasco\r
-      */\r
-     public interface ContainerActivity extends TransferServiceGetter {\r
\r
-         /**\r
-          * Callback method invoked when the detail fragment wants to notice its container \r
-          * activity about a relevant state the file shown by the fragment.\r
-          * \r
-          * Added to notify to FileDisplayActivity about the need of refresh the files list. \r
-          * \r
-          * Currently called when:\r
-          *  - a download is started;\r
-          *  - a rename is completed;\r
-          *  - a deletion is completed;\r
-          *  - the 'inSync' flag is changed;\r
-          */\r
-         public void onFileStateChanged();\r
-         \r
-     }\r
-     \r
\r
-     /**\r
-      * Once the file download has finished -> update view\r
-      * @author Bartek Przybylski\r
-      */\r
-     private class DownloadFinishReceiver extends BroadcastReceiver {\r
-         @Override\r
-         public void onReceive(Context context, Intent intent) {\r
-             String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);\r
\r
-             if (!isEmpty() && accountName.equals(mAccount.name)) {\r
-                 boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false);\r
-                 String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);\r
-                 if (mFile.getRemotePath().equals(downloadedRemotePath)) {\r
-                     if (downloadWasFine) {\r
-                         mFile = mStorageManager.getFileByPath(downloadedRemotePath);\r
-                     }\r
-                     updateFileDetails(false);    // it updates the buttons; must be called although !downloadWasFine\r
-                 }\r
-             }\r
-         }\r
-     }\r
-     \r
-     \r
-     /**\r
-      * Once the file upload has finished -> update view\r
-      * \r
-      * Being notified about the finish of an upload is necessary for the next sequence:\r
-      *   1. Upload a big file.\r
-      *   2. Force a synchronization; if it finished before the upload, the file in transfer will be included in the local database and in the file list\r
-      *      of its containing folder; the the server includes it in the PROPFIND requests although it's not fully upload. \r
-      *   3. Click the file in the list to see its details.\r
-      *   4. Wait for the upload finishes; at this moment, the details view must be refreshed to enable the action buttons.\r
-      */\r
-     private class UploadFinishReceiver extends BroadcastReceiver {\r
-         @Override\r
-         public void onReceive(Context context, Intent intent) {\r
-             String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);\r
\r
-             if (!isEmpty() && accountName.equals(mAccount.name)) {\r
-                 boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false);\r
-                 String uploadRemotePath = intent.getStringExtra(FileUploader.EXTRA_REMOTE_PATH);\r
-                 boolean renamedInUpload = mFile.getRemotePath().equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH));\r
-                 if (mFile.getRemotePath().equals(uploadRemotePath) ||\r
-                     renamedInUpload) {\r
-                     if (uploadWasFine) {\r
-                        mFile = mStorageManager.getFileByPath(uploadRemotePath);\r
-                     }\r
-                     if (renamedInUpload) {\r
-                         String newName = (new File(uploadRemotePath)).getName();\r
-                         Toast msg = Toast.makeText(getActivity().getApplicationContext(), String.format(getString(R.string.filedetails_renamed_in_upload_msg), newName), Toast.LENGTH_LONG);\r
-                         msg.show();\r
-                     }\r
-                     getSherlockActivity().removeStickyBroadcast(intent);    // not the best place to do this; a small refactorization of BroadcastReceivers should be done\r
-                     updateFileDetails(false);    // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server\r
-                 }\r
-             }\r
-         }\r
-     }\r
-     \r
\r
-     // this is a temporary class for sharing purposes, it need to be replaced in transfer service\r
-     /*\r
-     @SuppressWarnings("unused")\r
-     private class ShareRunnable implements Runnable {\r
-         private String mPath;\r
\r
-         public ShareRunnable(String path) {\r
-             mPath = path;\r
-         }\r
-         \r
-         public void run() {\r
-             AccountManager am = AccountManager.get(getActivity());\r
-             Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());\r
-             OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION));\r
-             String url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + AccountUtils.getWebdavPath(ocv);\r
\r
-             Log.d("share", "sharing for version " + ocv.toString());\r
\r
-             if (ocv.compareTo(new OwnCloudVersion(0x040000)) >= 0) {\r
-                 String APPS_PATH = "/apps/files_sharing/";\r
-                 String SHARE_PATH = "ajax/share.php";\r
\r
-                 String SHARED_PATH = "/apps/files_sharing/get.php?token=";\r
-                 \r
-                 final String WEBDAV_SCRIPT = "webdav.php";\r
-                 final String WEBDAV_FILES_LOCATION = "/files/";\r
-                 \r
-                 WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(account, getActivity().getApplicationContext());\r
-                 HttpConnectionManagerParams params = new HttpConnectionManagerParams();\r
-                 params.setMaxConnectionsPerHost(wc.getHostConfiguration(), 5);\r
\r
-                 //wc.getParams().setParameter("http.protocol.single-cookie-header", true);\r
-                 //wc.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);\r
\r
-                 PostMethod post = new PostMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + APPS_PATH + SHARE_PATH);\r
\r
-                 post.addRequestHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8" );\r
-                 post.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));\r
-                 List<NameValuePair> formparams = new ArrayList<NameValuePair>();\r
-                 Log.d("share", mPath+"");\r
-                 formparams.add(new BasicNameValuePair("sources",mPath));\r
-                 formparams.add(new BasicNameValuePair("uid_shared_with", "public"));\r
-                 formparams.add(new BasicNameValuePair("permissions", "0"));\r
-                 post.setRequestEntity(new StringRequestEntity(URLEncodedUtils.format(formparams, HTTP.UTF_8)));\r
\r
-                 int status;\r
-                 try {\r
-                     PropFindMethod find = new PropFindMethod(url+"/");\r
-                     find.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));\r
-                     Log.d("sharer", ""+ url+"/");\r
-                     \r
-                     for (org.apache.commons.httpclient.Header a : find.getRequestHeaders()) {\r
-                         Log.d("sharer-h", a.getName() + ":"+a.getValue());\r
-                     }\r
-                     \r
-                     int status2 = wc.executeMethod(find);\r
\r
-                     Log.d("sharer", "propstatus "+status2);\r
-                     \r
-                     GetMethod get = new GetMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + "/");\r
-                     get.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));\r
-                     \r
-                     status2 = wc.executeMethod(get);\r
\r
-                     Log.d("sharer", "getstatus "+status2);\r
-                     Log.d("sharer", "" + get.getResponseBodyAsString());\r
-                     \r
-                     for (org.apache.commons.httpclient.Header a : get.getResponseHeaders()) {\r
-                         Log.d("sharer", a.getName() + ":"+a.getValue());\r
-                     }\r
\r
-                     status = wc.executeMethod(post);\r
-                     for (org.apache.commons.httpclient.Header a : post.getRequestHeaders()) {\r
-                         Log.d("sharer-h", a.getName() + ":"+a.getValue());\r
-                     }\r
-                     for (org.apache.commons.httpclient.Header a : post.getResponseHeaders()) {\r
-                         Log.d("sharer", a.getName() + ":"+a.getValue());\r
-                     }\r
-                     String resp = post.getResponseBodyAsString();\r
-                     Log.d("share", ""+post.getURI().toString());\r
-                     Log.d("share", "returned status " + status);\r
-                     Log.d("share", " " +resp);\r
-                     \r
-                     if(status != HttpStatus.SC_OK ||resp == null || resp.equals("") || resp.startsWith("false")) {\r
-                         return;\r
-                      }\r
\r
-                     JSONObject jsonObject = new JSONObject (resp);\r
-                     String jsonStatus = jsonObject.getString("status");\r
-                     if(!jsonStatus.equals("success")) throw new Exception("Error while sharing file status != success");\r
-                     \r
-                     String token = jsonObject.getString("data");\r
-                     String uri = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + SHARED_PATH + token; \r
-                     Log.d("Actions:shareFile ok", "url: " + uri);   \r
-                     \r
-                 } catch (Exception e) {\r
-                     e.printStackTrace();\r
-                 }\r
-                 \r
-             } else if (ocv.compareTo(new OwnCloudVersion(0x030000)) >= 0) {\r
-                 \r
-             }\r
-         }\r
-     }\r
-     */\r
-     \r
-     public void onDismiss(EditNameDialog dialog) {\r
-         if (dialog.getResult()) {\r
-             String newFilename = dialog.getNewFilename();\r
-             Log.d(TAG, "name edit dialog dismissed with new name " + newFilename);\r
-             mLastRemoteOperation = new RenameFileOperation( mFile, \r
-                                                             mAccount, \r
-                                                             newFilename, \r
-                                                             new FileDataStorageManager(mAccount, getActivity().getContentResolver()));\r
-             mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());\r
-             boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
-             getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
-         }\r
-     }\r
-     \r
-     \r
-     class BitmapLoader extends AsyncTask<String, Void, Bitmap> {\r
-         @SuppressLint({ "NewApi", "NewApi", "NewApi" }) // to avoid Lint errors since Android SDK r20\r
-               @Override\r
-         protected Bitmap doInBackground(String... params) {\r
-             Bitmap result = null;\r
-             if (params.length != 1) return result;\r
-             String storagePath = params[0];\r
-             try {\r
\r
-                 BitmapFactory.Options options = new Options();\r
-                 options.inScaled = true;\r
-                 options.inPurgeable = true;\r
-                 options.inJustDecodeBounds = true;\r
-                 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {\r
-                     options.inPreferQualityOverSpeed = false;\r
-                 }\r
-                 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {\r
-                     options.inMutable = false;\r
-                 }\r
\r
-                 result = BitmapFactory.decodeFile(storagePath, options);\r
-                 options.inJustDecodeBounds = false;\r
\r
-                 int width = options.outWidth;\r
-                 int height = options.outHeight;\r
-                 int scale = 1;\r
-                 if (width >= 2048 || height >= 2048) {\r
-                     scale = (int) Math.ceil((Math.ceil(Math.max(height, width) / 2048.)));\r
-                     options.inSampleSize = scale;\r
-                 }\r
-                 Display display = getActivity().getWindowManager().getDefaultDisplay();\r
-                 Point size = new Point();\r
-                 int screenwidth;\r
-                 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {\r
-                     display.getSize(size);\r
-                     screenwidth = size.x;\r
-                 } else {\r
-                     screenwidth = display.getWidth();\r
-                 }\r
\r
-                 Log.e("ASD", "W " + width + " SW " + screenwidth);\r
\r
-                 if (width > screenwidth) {\r
-                     scale = (int) Math.ceil((float)width / screenwidth);\r
-                     options.inSampleSize = scale;\r
-                 }\r
\r
-                 result = BitmapFactory.decodeFile(storagePath, options);\r
\r
-                 Log.e("ASD", "W " + options.outWidth + " SW " + options.outHeight);\r
\r
-             } catch (OutOfMemoryError e) {\r
-                 result = null;\r
-                 Log.e(TAG, "Out of memory occured for file with size " + storagePath);\r
-                 \r
-             } catch (NoSuchFieldError e) {\r
-                 result = null;\r
-                 Log.e(TAG, "Error from access to unexisting field despite protection " + storagePath);\r
-                 \r
-             } catch (Throwable t) {\r
-                 result = null;\r
-                 Log.e(TAG, "Unexpected error while creating image preview " + storagePath, t);\r
-             }\r
-             return result;\r
-         }\r
-         @Override\r
-         protected void onPostExecute(Bitmap result) {\r
-             if (result != null && mPreview != null) {\r
-                 mPreview.setImageBitmap(result);\r
-             }\r
-         }\r
-         \r
-     }\r
\r
-     /**\r
-      * {@inheritDoc}\r
-      */\r
-     @Override\r
-     public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {\r
-         if (operation instanceof RemoveFileOperation) {\r
-             onRemoveFileOperationFinish((RemoveFileOperation)operation, result);\r
-                 \r
-         } else if (operation instanceof RenameFileOperation) {\r
-             onRenameFileOperationFinish((RenameFileOperation)operation, result);\r
-                 \r
-         } else if (operation instanceof SynchronizeFileOperation) {\r
-             onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);\r
-         }\r
-     }\r
-     \r
-     \r
-     private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {\r
-         boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
-         getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
-         \r
-         if (result.isSuccess()) {\r
-             Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);\r
-             msg.show();\r
-             if (inDisplayActivity) {\r
-                 // double pane\r
-                 FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();\r
-                 transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment\r
-                 transaction.commit();\r
-                 mContainerActivity.onFileStateChanged();\r
-             } else {\r
-                 getActivity().finish();\r
-             }\r
-                 \r
-         } else {\r
-             Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); \r
-             msg.show();\r
-             if (result.isSslRecoverableException()) {\r
-                 // TODO show the SSL warning dialog\r
-             }\r
-         }\r
-     }\r
-     \r
-     private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) {\r
-         boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
-         getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
-         \r
-         if (result.isSuccess()) {\r
-             updateFileDetails(((RenameFileOperation)operation).getFile(), mAccount);\r
-             mContainerActivity.onFileStateChanged();\r
-             \r
-         } else {\r
-             if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {\r
-                 Toast msg = Toast.makeText(getActivity(), R.string.rename_local_fail_msg, Toast.LENGTH_LONG); \r
-                 msg.show();\r
-                 // TODO throw again the new rename dialog\r
-             } else {\r
-                 Toast msg = Toast.makeText(getActivity(), R.string.rename_server_fail_msg, Toast.LENGTH_LONG); \r
-                 msg.show();\r
-                 if (result.isSslRecoverableException()) {\r
-                     // TODO show the SSL warning dialog\r
-                 }\r
-             }\r
-         }\r
-     }\r
-     \r
-     private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {\r
-         boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
-         getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
\r
-         if (!result.isSuccess()) {\r
-             if (result.getCode() == ResultCode.SYNC_CONFLICT) {\r
-                 Intent i = new Intent(getActivity(), ConflictsResolveActivity.class);\r
-                 i.putExtra(ConflictsResolveActivity.EXTRA_FILE, mFile);\r
-                 i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, mAccount);\r
-                 startActivity(i);\r
-                 \r
-             } else {\r
-                 Toast msg = Toast.makeText(getActivity(), R.string.sync_file_fail_msg, Toast.LENGTH_LONG); \r
-                 msg.show();\r
-             }\r
-             \r
-             if (mFile.isDown()) {\r
-                 setButtonsForDown();\r
-                 \r
-             } else {\r
-                 setButtonsForRemote();\r
-             }\r
-             \r
-         } else {\r
-             if (operation.transferWasRequested()) {\r
-                 mContainerActivity.onFileStateChanged();    // this is not working; FileDownloader won't do NOTHING at all until this method finishes, so \r
-                                                             // checking the service to see if the file is downloading results in FALSE\r
-             } else {\r
-                 Toast msg = Toast.makeText(getActivity(), R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); \r
-                 msg.show();\r
-                 if (mFile.isDown()) {\r
-                     setButtonsForDown();\r
-                     \r
-                 } else {\r
-                     setButtonsForRemote();\r
-                 }\r
-             }\r
-         }\r
-     }\r
\r
- }\r
+             case R.id.fdKeepInSync: {
+                 CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync);
+                 mFile.setKeepInSync(cb.isChecked());
+                 mStorageManager.saveFile(mFile);
+                 
+                 /// register the OCFile instance in the observer service to monitor local updates;
+                 /// if necessary, the file is download 
+                 Intent intent = new Intent(getActivity().getApplicationContext(),
+                                            FileObserverService.class);
+                 intent.putExtra(FileObserverService.KEY_FILE_CMD,
+                            (cb.isChecked()?
+                                    FileObserverService.CMD_ADD_OBSERVED_FILE:
+                                    FileObserverService.CMD_DEL_OBSERVED_FILE));
+                 intent.putExtra(FileObserverService.KEY_CMD_ARG_FILE, mFile);
+                 intent.putExtra(FileObserverService.KEY_CMD_ARG_ACCOUNT, mAccount);
+                 getActivity().startService(intent);
+                 
+                 if (mFile.keepInSync()) {
+                     onClick(getView().findViewById(R.id.fdDownloadBtn));    // force an immediate synchronization
+                 }
+                 break;
+             }
+             case R.id.fdRenameBtn: {
+                 String fileName = mFile.getFileName();
+                 int extensionStart = mFile.isDirectory() ? -1 : fileName.lastIndexOf(".");
+                 int selectionEnd = (extensionStart >= 0) ? extensionStart : fileName.length();
+                 EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), fileName, 0, selectionEnd, this);
+                 dialog.show(getFragmentManager(), "nameeditdialog");
+                 break;
+             }   
+             case R.id.fdRemoveBtn: {
+                 ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(
+                         R.string.confirmation_remove_alert,
+                         new String[]{mFile.getFileName()},
+                         mFile.isDown() ? R.string.confirmation_remove_remote_and_local : R.string.confirmation_remove_remote,
+                         mFile.isDown() ? R.string.confirmation_remove_local : -1,
+                         R.string.common_cancel);
+                 confDialog.setOnConfirmationListener(this);
+                 confDialog.show(getFragmentManager(), FTAG_CONFIRMATION);
+                 break;
+             }
+             case R.id.fdOpenBtn: {
+                 openFile();
+                 break;
+             }
+             default:
+                 Log_OC.e(TAG, "Incorrect view clicked!");
+         }
+         
 -        /* else if (v.getId() == R.id.fdShareBtn) {
 -            Thread t = new Thread(new ShareRunnable(mFile.getRemotePath()));
 -            t.start();
 -        }*/
 -    }
 -    
 -    
++    }\r
++    \r
+     /**
+      * Opens mFile.
+      */
+     private void openFile() {
+         
+         String storagePath = mFile.getStoragePath();
+         String encodedStoragePath = WebdavUtils.encodePath(storagePath);
+         try {
+             Intent i = new Intent(Intent.ACTION_VIEW);
+             i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype());
+             i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+             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 {
+                 Intent i = new Intent(Intent.ACTION_VIEW);
+                 mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
+                 if (mimeType == null || !mimeType.equals(mFile.getMimetype())) {
+                     if (mimeType != null) {
+                         i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);
+                     } else {
+                         // desperate try
+                         i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*/*");
+                     }
+                     i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+                     startActivity(i);
+                     toastIt = false;
+                 }
+                 
+             } 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) {
+                     Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();
+                 }
+             }
+             
+         }
+     }
 -
+     @Override
+     public void onConfirmation(String callerTag) {
+         if (callerTag.equals(FTAG_CONFIRMATION)) {
+             if (mStorageManager.getFileById(mFile.getFileId()) != null) {
+                 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);
+             }
+         }
+     }
+     
+     @Override
+     public void onNeutral(String callerTag) {
+         File f = null;
+         if (mFile.isDown() && (f = new File(mFile.getStoragePath())).exists()) {
+             f.delete();
+             mFile.setStoragePath(null);
+             mStorageManager.saveFile(mFile);
+             updateFileDetails(mFile, mAccount);
+         }
+     }
+     
+     @Override
+     public void onCancel(String callerTag) {
 -        Log.d(TAG, "REMOVAL CANCELED");
++        Log_OC.d(TAG, "REMOVAL CANCELED");
+     }
+     
+     
+     /**
+      * Check if the fragment was created with an empty layout. An empty fragment can't show file details, must be replaced.
+      * 
+      * @return  True when the fragment was created with the empty layout.
+      */
+     public boolean isEmpty() {
+         return (mLayout == R.layout.file_details_empty || mFile == null || mAccount == null);
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     public OCFile getFile(){
+         return mFile;
+     }
+     
+     /**
+      * Use this method to signal this Activity that it shall update its view.
+      * 
+      * @param file : An {@link OCFile}
+      */
+     public void updateFileDetails(OCFile file, Account ocAccount) {
+         mFile = file;
+         if (ocAccount != null && ( 
+                 mStorageManager == null || 
+                 (mAccount != null && !mAccount.equals(ocAccount))
+            )) {
+             mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());
+         }
+         mAccount = ocAccount;
+         updateFileDetails(false, false);
+     }
+     /**
+      * Updates the view with all relevant details about that file.
+      *
+      * TODO Remove parameter when the transferring state of files is kept in database. 
+      * 
+      * TODO REFACTORING! this method called 5 times before every time the fragment is shown! 
+      * 
+      * @param transferring      Flag signaling if the file should be considered as downloading or uploading, 
+      *                          although {@link FileDownloaderBinder#isDownloading(Account, OCFile)}  and 
+      *                          {@link FileUploaderBinder#isUploading(Account, OCFile)} return false.
+      *                          
+      * @param refresh           If 'true', try to refresh the hold file from the database
+      */
+     public void updateFileDetails(boolean transferring, boolean refresh) {
+         if (readyToShow()) {
+             
+             if (refresh && mStorageManager != null) {
+                 mFile = mStorageManager.getFileByPath(mFile.getRemotePath());
+             }
+             
+             // set file details
+             setFilename(mFile.getFileName());
+             setFiletype(mFile.getMimetype());
+             setFilesize(mFile.getFileLength());
+             if(ocVersionSupportsTimeCreated()){
+                 setTimeCreated(mFile.getCreationTimestamp());
+             }
+            
+             setTimeModified(mFile.getModificationTimestamp());
+             
+             CheckBox cb = (CheckBox)getView().findViewById(R.id.fdKeepInSync);
+             cb.setChecked(mFile.keepInSync());
+             // configure UI for depending upon local state of the file
+             //if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath()) || FileUploader.isUploading(mAccount, mFile.getRemotePath())) {
+             FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
+             FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
+             if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) || (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile))) {
+                 setButtonsForTransferring();
+                 
+             } else if (mFile.isDown()) {
+                 
+                 setButtonsForDown();
+                 
+             } else {
+                 // TODO load default preview image; when the local file is removed, the preview remains there
+                 setButtonsForRemote();
+             }
+         }
+         getView().invalidate();
+     }
+     
 -    
+     /**
+      * Checks if the fragment is ready to show details of a OCFile
+      *  
+      * @return  'True' when the fragment is ready to show details of a file
+      */
+     private boolean readyToShow() {
+         return (mFile != null && mAccount != null && mLayout == R.layout.file_details_fragment);        
+     }
+     /**
+      * Updates the filename in view
+      * @param filename to set
+      */
+     private void setFilename(String filename) {
+         TextView tv = (TextView) getView().findViewById(R.id.fdFilename);
+         if (tv != null)
+             tv.setText(filename);
+     }
+     /**
+      * Updates the MIME type in view
+      * @param mimetype to set
+      */
+     private void setFiletype(String mimetype) {
+         TextView tv = (TextView) getView().findViewById(R.id.fdType);
+         if (tv != null) {
+             String printableMimetype = DisplayUtils.convertMIMEtoPrettyPrint(mimetype);;        
+             tv.setText(printableMimetype);
+         }
+         ImageView iv = (ImageView) getView().findViewById(R.id.fdIcon);
+         if (iv != null) {
+             iv.setImageResource(DisplayUtils.getResourceId(mimetype));
+         }
+     }
+     /**
+      * Updates the file size in view
+      * @param filesize in bytes to set
+      */
+     private void setFilesize(long filesize) {
+         TextView tv = (TextView) getView().findViewById(R.id.fdSize);
+         if (tv != null)
+             tv.setText(DisplayUtils.bytesToHumanReadable(filesize));
+     }
+     
+     /**
+      * Updates the time that the file was created in view
+      * @param milliseconds Unix time to set
+      */
+     private void setTimeCreated(long milliseconds){
+         TextView tv = (TextView) getView().findViewById(R.id.fdCreated);
+         TextView tvLabel = (TextView) getView().findViewById(R.id.fdCreatedLabel);
+         if(tv != null){
+             tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));
+             tv.setVisibility(View.VISIBLE);
+             tvLabel.setVisibility(View.VISIBLE);
+         }
+     }
+     
+     /**
+      * Updates the time that the file was last modified
+      * @param milliseconds Unix time to set
+      */
+     private void setTimeModified(long milliseconds){
+         TextView tv = (TextView) getView().findViewById(R.id.fdModified);
+         if(tv != null){
+             tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));
+         }
+     }
+     
+     /**
+      * Enables or disables buttons for a file being downloaded
+      */
+     private void setButtonsForTransferring() {
+         if (!isEmpty()) {
+             Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);
+             downloadButton.setText(R.string.common_cancel);
+             //downloadButton.setEnabled(false);
+         
+             // let's protect the user from himself ;)
+             ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false);
+             ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(false);
+             ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(false);
+             getView().findViewById(R.id.fdKeepInSync).setEnabled(false);
+             
+             // show the progress bar for the transfer
+             ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.fdProgressBar);
+             progressBar.setVisibility(View.VISIBLE);
+             TextView progressText = (TextView)getView().findViewById(R.id.fdProgressText);
+             progressText.setVisibility(View.VISIBLE);
+             FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
+             FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
+             if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {
+                 progressText.setText(R.string.downloader_download_in_progress_ticker);
+             } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile)) {
+                 progressText.setText(R.string.uploader_upload_in_progress_ticker);
+             }
+         }
+     }
+     /**
+      * Enables or disables buttons for a file locally available 
+      */
+     private void setButtonsForDown() {
+         if (!isEmpty()) {
+             Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);
+             downloadButton.setText(R.string.filedetails_sync_file);
+         
+             ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(true);
+             ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);
+             ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true);
+             getView().findViewById(R.id.fdKeepInSync).setEnabled(true);
+             
+             // hides the progress bar
+             ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.fdProgressBar);
+             progressBar.setVisibility(View.GONE);
+             TextView progressText = (TextView)getView().findViewById(R.id.fdProgressText);
+             progressText.setVisibility(View.GONE);
+         }
+     }
+     /**
+      * Enables or disables buttons for a file not locally available 
+      */
+     private void setButtonsForRemote() {
+         if (!isEmpty()) {
+             Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);
+             downloadButton.setText(R.string.filedetails_download);
+             
+             ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false);
+             ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);
+             ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true);
+             getView().findViewById(R.id.fdKeepInSync).setEnabled(true);
+             
+             // hides the progress bar
+             ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.fdProgressBar);
+             progressBar.setVisibility(View.GONE);
+             TextView progressText = (TextView)getView().findViewById(R.id.fdProgressText);
+             progressText.setVisibility(View.GONE);
+         }
+     }
+     
+     /**
+      * In ownCloud 3.X.X and 4.X.X there is a bug that SabreDAV does not return
+      * the time that the file was created. There is a chance that this will
+      * be fixed in future versions. Use this method to check if this version of
+      * ownCloud has this fix.
+      * @return True, if ownCloud the ownCloud version is supporting creation time
+      */
+     private boolean ocVersionSupportsTimeCreated(){
+         /*if(mAccount != null){
+             AccountManager accManager = (AccountManager) getActivity().getSystemService(Context.ACCOUNT_SERVICE);
+             OwnCloudVersion ocVersion = new OwnCloudVersion(accManager
+                     .getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION));
+             if(ocVersion.compareTo(new OwnCloudVersion(0x030000)) < 0) {
+                 return true;
+             }
+         }*/
+         return false;
+     }
+     
+     /**
+      * Once the file upload has finished -> update view
+      * 
+      * Being notified about the finish of an upload is necessary for the next sequence:
+      *   1. Upload a big file.
+      *   2. Force a synchronization; if it finished before the upload, the file in transfer will be included in the local database and in the file list
+      *      of its containing folder; the the server includes it in the PROPFIND requests although it's not fully upload. 
+      *   3. Click the file in the list to see its details.
+      *   4. Wait for the upload finishes; at this moment, the details view must be refreshed to enable the action buttons.
+      */
+     private class UploadFinishReceiver extends BroadcastReceiver {
+         @Override
+         public void onReceive(Context context, Intent intent) {
+             String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);
+             if (!isEmpty() && accountName.equals(mAccount.name)) {
+                 boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false);
+                 String uploadRemotePath = intent.getStringExtra(FileUploader.EXTRA_REMOTE_PATH);
+                 boolean renamedInUpload = mFile.getRemotePath().equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH));
+                 if (mFile.getRemotePath().equals(uploadRemotePath) ||
+                     renamedInUpload) {
+                     if (uploadWasFine) {
+                         mFile = mStorageManager.getFileByPath(uploadRemotePath);
+                     }
+                     if (renamedInUpload) {
+                         String newName = (new File(uploadRemotePath)).getName();
+                         Toast msg = Toast.makeText(getActivity().getApplicationContext(), String.format(getString(R.string.filedetails_renamed_in_upload_msg), newName), Toast.LENGTH_LONG);
+                         msg.show();
+                     }
+                     getSherlockActivity().removeStickyBroadcast(intent);    // not the best place to do this; a small refactorization of BroadcastReceivers should be done
+                     updateFileDetails(false, false);    // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server
+                 }
+             }
+         }
+     }
+     
 -    // 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);
+         }
+     }
+     
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+         if (operation.equals(mLastRemoteOperation)) {
+             if (operation instanceof RemoveFileOperation) {
+                 onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
+                 
+             } else if (operation instanceof RenameFileOperation) {
+                 onRenameFileOperationFinish((RenameFileOperation)operation, result);
+                 
+             } else if (operation instanceof SynchronizeFileOperation) {
+                 onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);
+             }
+         }
+     }
+     
+     
+     private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
+         boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
+         getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
+         
+         if (result.isSuccess()) {
+             Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);
+             msg.show();
+             if (inDisplayActivity) {
+                 // double pane
+                 FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
+                 transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment
+                 transaction.commit();
+                 mContainerActivity.onFileStateChanged();
+             } else {
+                 getActivity().finish();
+             }
+                 
+         } else {
+             Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); 
+             msg.show();
+             if (result.isSslRecoverableException()) {
+                 // TODO show the SSL warning dialog
+             }
+         }
+     }
+     
+     private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) {
+         boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
+         getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
+         
+         if (result.isSuccess()) {
+             updateFileDetails(((RenameFileOperation)operation).getFile(), mAccount);
+             mContainerActivity.onFileStateChanged();
+             
+         } else {
+             if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {
+                 Toast msg = Toast.makeText(getActivity(), R.string.rename_local_fail_msg, Toast.LENGTH_LONG); 
+                 msg.show();
+                 // TODO throw again the new rename dialog
+             } else {
+                 Toast msg = Toast.makeText(getActivity(), R.string.rename_server_fail_msg, Toast.LENGTH_LONG); 
+                 msg.show();
+                 if (result.isSslRecoverableException()) {
+                     // TODO show the SSL warning dialog
+                 }
+             }
+         }
+     }
+     
+     private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {
+         boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
+         getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
+         if (!result.isSuccess()) {
+             if (result.getCode() == ResultCode.SYNC_CONFLICT) {
+                 Intent i = new Intent(getActivity(), ConflictsResolveActivity.class);
+                 i.putExtra(ConflictsResolveActivity.EXTRA_FILE, mFile);
+                 i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, mAccount);
+                 startActivity(i);
+                 
+             } else {
+                 Toast msg = Toast.makeText(getActivity(), R.string.sync_file_fail_msg, Toast.LENGTH_LONG); 
+                 msg.show();
+             }
+             
+             if (mFile.isDown()) {
+                 setButtonsForDown();
+                 
+             } else {
+                 setButtonsForRemote();
+             }
+             
+         } else {
+             if (operation.transferWasRequested()) {
+                 setButtonsForTransferring();
+                 mContainerActivity.onFileStateChanged();    // this is not working; FileDownloader won't do NOTHING at all until this method finishes, so 
+                                                             // checking the service to see if the file is downloading results in FALSE
+             } else {
+                 Toast msg = Toast.makeText(getActivity(), R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); 
+                 msg.show();
+                 if (mFile.isDown()) {
+                     setButtonsForDown();
+                     
+                 } else {
+                     setButtonsForRemote();
+                 }
+             }
+         }
+     }
+     
 -    
++
+     public void listenForTransferProgress() {
+         if (mProgressListener != null) {
+             if (mContainerActivity.getFileDownloaderBinder() != null) {
+                 mContainerActivity.getFileDownloaderBinder().addDatatransferProgressListener(mProgressListener, mAccount, mFile);
+             }
+             if (mContainerActivity.getFileUploaderBinder() != null) {
+                 mContainerActivity.getFileUploaderBinder().addDatatransferProgressListener(mProgressListener, mAccount, mFile);
+             }
+         }
+     }
+     
+     
+     public void leaveTransferProgress() {
+         if (mProgressListener != null) {
+             if (mContainerActivity.getFileDownloaderBinder() != null) {
+                 mContainerActivity.getFileDownloaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, mFile);
+             }
+             if (mContainerActivity.getFileUploaderBinder() != null) {
+                 mContainerActivity.getFileUploaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, mFile);
+             }
+         }
+     }
+     
+     /**
+      * Helper class responsible for updating the progress bar shown for file uploading or downloading  
+      * 
+      * @author David A. Velasco
+      */
+     private class ProgressListener implements OnDatatransferProgressListener {
+         int mLastPercent = 0;
+         WeakReference<ProgressBar> mProgressBar = null;
+         
+         ProgressListener(ProgressBar progressBar) {
+             mProgressBar = new WeakReference<ProgressBar>(progressBar);
+         }
+         
+         @Override
+         public void onTransferProgress(long progressRate) {
+             // old method, nothing here
+         };
+         @Override
+         public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filename) {
+             int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));
+             if (percent != mLastPercent) {
+                 ProgressBar pb = mProgressBar.get();
+                 if (pb != null) {
+                     pb.setProgress(percent);
+                     pb.postInvalidate();
+                 }
+             }
+             mLastPercent = percent;
+         }
+     };
 -}
++    /*
++    // 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) {
++                
++            }
++        }
++    }
++    */
++    
++}
@@@ -26,7 -25,7 +25,6 @@@ import com.owncloud.android.ui.adapter.
  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;
@@@ -50,8 -52,7 +50,6 @@@ import android.content.Intent
  import android.net.Uri;
  import android.os.Bundle;
  import android.os.Handler;
- import android.support.v4.app.DialogFragment;
--import android.util.Log;
  import android.view.ContextMenu;
  import android.view.MenuInflater;
  import android.view.MenuItem;
@@@ -312,10 -314,11 +311,10 @@@ public class OCFileListFragment extend
                  }
                  return true;
              }
-             case R.id.download_file_item: {
+             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;
              }
index 0000000,b11d341..773350a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,396 +1,396 @@@
 - *   it under the terms of the GNU General Public License as published by
 - *   the Free Software Foundation, either version 3 of the License.
+ /* ownCloud Android client application
+  * 
+  *   Copyright (C) 2012-2013  ownCloud Inc.
+  *
+  *   This program is free software: you can redistribute it and/or modify
 -import android.util.Log;
++ *   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.preview;
+ import java.lang.ref.WeakReference;
+ import android.accounts.Account;
+ import android.app.Activity;
+ import android.os.Bundle;
+ import android.support.v4.app.FragmentStatePagerAdapter;
 -                Log.e(TAG, "Incorrect view clicked!");
+ import android.view.LayoutInflater;
+ import android.view.View;
+ import android.view.View.OnClickListener;
+ import android.view.ViewGroup;
+ import android.widget.Button;
+ import android.widget.ProgressBar;
+ import android.widget.TextView;
+ import com.actionbarsherlock.app.SherlockFragment;
+ import com.owncloud.android.datamodel.FileDataStorageManager;
+ 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;
+ /**
+  * This Fragment is used to monitor the progress of a file downloading.
+  * 
+  * @author David A. Velasco
+  */
+ public class FileDownloadFragment extends SherlockFragment implements OnClickListener, FileFragment {
+     public static final String EXTRA_FILE = "FILE";
+     public static final String EXTRA_ACCOUNT = "ACCOUNT";
+     private static final String EXTRA_ERROR = "ERROR";
+     private FileFragment.ContainerActivity mContainerActivity;
+     
+     private View mView;
+     private OCFile mFile;
+     private Account mAccount;
+     private FileDataStorageManager mStorageManager;
+     
+     public ProgressListener mProgressListener;
+     private boolean mListening;
+     
+     private static final String TAG = FileDownloadFragment.class.getSimpleName();
+     
+     private boolean mIgnoreFirstSavedState;
+     private boolean mError;
+     
+     /**
+      * Creates an empty details fragment.
+      * 
+      * It's necessary to keep a public constructor without parameters; the system uses it when tries to reinstantiate a fragment automatically. 
+      */
+     public FileDownloadFragment() {
+         mFile = null;
+         mAccount = null;
+         mStorageManager = null;
+         mProgressListener = null;
+         mListening = false;
+         mIgnoreFirstSavedState = false;
+         mError = false;
+     }
+     
+     
+     /**
+      * Creates a details fragment.
+      * 
+      * When 'fileToDetail' or 'ocAccount' are null, creates a dummy layout (to use when a file wasn't tapped before).
+      * 
+      * @param fileToDetail      An {@link OCFile} to show in the fragment
+      * @param ocAccount         An ownCloud account; needed to start downloads
+      * @param ignoreFirstSavedState     Flag to work around an unexpected behaviour of {@link FragmentStatePagerAdapter}; TODO better solution 
+      */
+     public FileDownloadFragment(OCFile fileToDetail, Account ocAccount, boolean ignoreFirstSavedState) {
+         mFile = fileToDetail;
+         mAccount = ocAccount;
+         mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment 
+         mProgressListener = null;
+         mListening = false;
+         mIgnoreFirstSavedState = ignoreFirstSavedState;
+         mError = false;
+     }
+     
+     
+     @Override
+     public void onCreate(Bundle savedInstanceState) {
+         super.onCreate(savedInstanceState);
+     }
+     
+     @Override
+     public View onCreateView(LayoutInflater inflater, ViewGroup container,
+             Bundle savedInstanceState) {
+         super.onCreateView(inflater, container, savedInstanceState);
+         
+         if (savedInstanceState != null) {
+             if (!mIgnoreFirstSavedState) {
+                 mFile = savedInstanceState.getParcelable(FileDownloadFragment.EXTRA_FILE);
+                 mAccount = savedInstanceState.getParcelable(FileDownloadFragment.EXTRA_ACCOUNT);
+                 mError = savedInstanceState.getBoolean(FileDownloadFragment.EXTRA_ERROR);
+             } else {
+                 mIgnoreFirstSavedState = false;
+             }
+         }
+         
+         View view = null;
+         view = inflater.inflate(R.layout.file_download_fragment, container, false);
+         mView = view;
+         
+         ProgressBar progressBar = (ProgressBar)mView.findViewById(R.id.progressBar);
+         mProgressListener = new ProgressListener(progressBar);
+         
+         ((Button)mView.findViewById(R.id.cancelBtn)).setOnClickListener(this);
+         
+         if (mError) {
+             setButtonsForRemote();
+         } else {
+             setButtonsForTransferring();
+         }
+         
+         return view;
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onAttach(Activity activity) {
+         super.onAttach(activity);
+         try {
+             mContainerActivity = (ContainerActivity) activity;
+             
+         } catch (ClassCastException e) {
+             throw new ClassCastException(activity.toString() + " must implement " + FileFragment.ContainerActivity.class.getSimpleName());
+         }
+     }
+     
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onActivityCreated(Bundle savedInstanceState) {
+         super.onActivityCreated(savedInstanceState);
+         if (mAccount != null) {
+             mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());;
+         }
+     }
+         
+     @Override
+     public void onSaveInstanceState(Bundle outState) {
+         super.onSaveInstanceState(outState);
+         outState.putParcelable(FileDownloadFragment.EXTRA_FILE, mFile);
+         outState.putParcelable(FileDownloadFragment.EXTRA_ACCOUNT, mAccount);
+         outState.putBoolean(FileDownloadFragment.EXTRA_ERROR, mError);
+     }
+     @Override
+     public void onStart() {
+         super.onStart();
+         listenForTransferProgress();
+     }
+     
+     @Override
+     public void onResume() {
+         super.onResume();
+     }
+     @Override
+     public void onPause() {
+         super.onPause();
+     }
+     
+     @Override
+     public void onStop() {
+         super.onStop();
+         leaveTransferProgress();
+     }
+     
+     @Override
+     public void onDestroy() {
+         super.onDestroy();
+     }
+     
+     
+     @Override
+     public View getView() {
+         if (!mListening) {
+             listenForTransferProgress();
+         }
+         return super.getView() == null ? mView : super.getView();
+     }
+     
+     @Override
+     public void onClick(View v) {
+         switch (v.getId()) {
+             case R.id.cancelBtn: {
+                 FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
+                 if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {
+                     downloaderBinder.cancel(mAccount, mFile);
+                     getActivity().finish(); // :)
+                     /*
+                     leaveTransferProgress();
+                     if (mFile.isDown()) {
+                         setButtonsForDown();
+                     } else {
+                         setButtonsForRemote();
+                     }
+                     */
+                 }
+                 break;
+             }
+             default:
++                Log_OC.e(TAG, "Incorrect view clicked!");
+         }
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     public OCFile getFile(){
+         return mFile;
+     }
+     
+     
+     /**
+      * Updates the view depending upon the state of the downloading file.
+      * 
+      * @param   transferring    When true, the view must be updated assuming that the holded file is 
+      *                          downloading, no matter what the downloaderBinder says.
+      */
+     public void updateView(boolean transferring) {
+         // configure UI for depending upon local state of the file
+         FileDownloaderBinder downloaderBinder = (mContainerActivity == null) ? null : mContainerActivity.getFileDownloaderBinder();
+         if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile))) {
+             setButtonsForTransferring();
+             
+         } else if (mFile.isDown()) {
+             
+             setButtonsForDown();
+             
+         } else {
+             setButtonsForRemote();
+         }
+         getView().invalidate();
+         
+     }
+     /**
+      * Enables or disables buttons for a file being downloaded
+      */
+     private void setButtonsForTransferring() {
+         getView().findViewById(R.id.cancelBtn).setVisibility(View.VISIBLE);
+     
+         // show the progress bar for the transfer
+         getView().findViewById(R.id.progressBar).setVisibility(View.VISIBLE);
+         TextView progressText = (TextView)getView().findViewById(R.id.progressText);
+         progressText.setText(R.string.downloader_download_in_progress_ticker);
+         progressText.setVisibility(View.VISIBLE);
+                 
+         // hides the error icon
+         getView().findViewById(R.id.errorText).setVisibility(View.GONE);
+         getView().findViewById(R.id.error_image).setVisibility(View.GONE);
+     }
+     
+     /**
+      * Enables or disables buttons for a file locally available 
+      */
+     private void setButtonsForDown() {
+         getView().findViewById(R.id.cancelBtn).setVisibility(View.GONE);
+     
+         // hides the progress bar
+         getView().findViewById(R.id.progressBar).setVisibility(View.GONE);
+         
+         // updates the text message
+         TextView progressText = (TextView)getView().findViewById(R.id.progressText);
+         progressText.setText(R.string.common_loading);
+         progressText.setVisibility(View.VISIBLE);
+         
+         // hides the error icon
+         getView().findViewById(R.id.errorText).setVisibility(View.GONE);
+         getView().findViewById(R.id.error_image).setVisibility(View.GONE);
+     }
+     
+     /**
+      * Enables or disables buttons for a file not locally available 
+      * 
+      * Currently, this is only used when a download was failed
+      */
+     private void setButtonsForRemote() {
+         getView().findViewById(R.id.cancelBtn).setVisibility(View.GONE);
+         
+         // hides the progress bar and message
+         getView().findViewById(R.id.progressBar).setVisibility(View.GONE);
+         getView().findViewById(R.id.progressText).setVisibility(View.GONE);
+         // shows the error icon and message
+         getView().findViewById(R.id.errorText).setVisibility(View.VISIBLE);
+         getView().findViewById(R.id.error_image).setVisibility(View.VISIBLE);
+     }
+     
+     public void listenForTransferProgress() {
+         if (mProgressListener != null && !mListening) {
+             if (mContainerActivity.getFileDownloaderBinder() != null) {
+                 mContainerActivity.getFileDownloaderBinder().addDatatransferProgressListener(mProgressListener, mAccount, mFile);
+                 mListening = true;
+                 setButtonsForTransferring();
+             }
+         }
+     }
+     
+     
+     public void leaveTransferProgress() {
+         if (mProgressListener != null) {
+             if (mContainerActivity.getFileDownloaderBinder() != null) {
+                 mContainerActivity.getFileDownloaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, mFile);
+                 mListening = false;
+             }
+         }
+     }
+     
+     /**
+      * Helper class responsible for updating the progress bar shown for file uploading or downloading  
+      * 
+      * @author David A. Velasco
+      */
+     private class ProgressListener implements OnDatatransferProgressListener {
+         int mLastPercent = 0;
+         WeakReference<ProgressBar> mProgressBar = null;
+         
+         ProgressListener(ProgressBar progressBar) {
+             mProgressBar = new WeakReference<ProgressBar>(progressBar);
+         }
+         
+         @Override
+         public void onTransferProgress(long progressRate) {
+             // old method, nothing here
+         };
+         @Override
+         public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filename) {
+             int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));
+             if (percent != mLastPercent) {
+                 ProgressBar pb = mProgressBar.get();
+                 if (pb != null) {
+                     pb.setProgress(percent);
+                     pb.postInvalidate();
+                 }
+             }
+             mLastPercent = percent;
+         }
+     }
+     public void setError(boolean error) {
+         mError = error;
+     };
+     
+ }
index 0000000,be06c59..9b3e7d8
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,448 +1,445 @@@
 -import org.apache.commons.httpclient.methods.PostMethod;
 -
+ /* 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.preview;
 -import android.support.v4.app.Fragment;
+ import android.accounts.Account;
+ import android.app.Dialog;
+ import android.app.ProgressDialog;
+ import android.content.BroadcastReceiver;
+ import android.content.ComponentName;
+ import android.content.Context;
+ import android.content.Intent;
+ import android.content.IntentFilter;
+ import android.content.ServiceConnection;
+ import android.os.Bundle;
+ import android.os.IBinder;
 -import android.util.Log;
+ import android.support.v4.view.ViewPager;
 -                    Log.d(TAG, "Simulating reselection of current page after connection of download binder");
+ import android.view.MotionEvent;
+ import android.view.View;
+ import android.view.View.OnTouchListener;
+ import com.actionbarsherlock.app.ActionBar;
+ import com.actionbarsherlock.app.SherlockFragmentActivity;
+ import com.actionbarsherlock.view.MenuItem;
+ import com.actionbarsherlock.view.Window;
+ import com.owncloud.android.datamodel.DataStorageManager;
+ import com.owncloud.android.datamodel.FileDataStorageManager;
+ import com.owncloud.android.datamodel.OCFile;
+ import com.owncloud.android.files.services.FileDownloader;
+ import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+ import com.owncloud.android.files.services.FileUploader;
+ import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+ import com.owncloud.android.ui.activity.FileDetailActivity;
+ 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;
+ /**
+  *  Used as an utility to preview image files contained in an ownCloud account.
+  *  
+  *  @author David A. Velasco
+  */
+ public class PreviewImageActivity extends SherlockFragmentActivity implements FileFragment.ContainerActivity, ViewPager.OnPageChangeListener, OnTouchListener {
+     
+     public static final int DIALOG_SHORT_WAIT = 0;
+     public static final String TAG = PreviewImageActivity.class.getSimpleName();
+     
+     public static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW";
+     private static final String KEY_WAITING_FOR_BINDER = "WAITING_FOR_BINDER";
+     
+     private OCFile mFile;
+     private OCFile mParentFolder;  
+     private Account mAccount;
+     private DataStorageManager mStorageManager;
+     
+     private ViewPager mViewPager; 
+     private PreviewImagePagerAdapter mPreviewImagePagerAdapter;    
+     
+     private FileDownloaderBinder mDownloaderBinder = null;
+     private ServiceConnection mDownloadConnection, mUploadConnection = null;
+     private FileUploaderBinder mUploaderBinder = null;
+     private boolean mRequestWaitingForBinder;
+     
+     private DownloadFinishReceiver mDownloadFinishReceiver;
+     private boolean mFullScreen;
+     
+     @Override
+     protected void onCreate(Bundle savedInstanceState) {
+         super.onCreate(savedInstanceState);
+         mFile = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);
+         mAccount = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);
+         if (mFile == null) {
+             throw new IllegalStateException("Instanced with a NULL OCFile");
+         }
+         if (mAccount == null) {
+             throw new IllegalStateException("Instanced with a NULL ownCloud Account");
+         }
+         if (!mFile.isImage()) {
+             throw new IllegalArgumentException("Non-image file passed as argument");
+         }
+         requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
+         setContentView(R.layout.preview_image_activity);
+     
+         ActionBar actionBar = getSupportActionBar();
+         actionBar.setDisplayHomeAsUpEnabled(true);
+         actionBar.setTitle(mFile.getFileName());
+         actionBar.hide();
+         
+         mFullScreen = true;
+         
+         mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
+         mParentFolder = mStorageManager.getFileById(mFile.getParentId());
+         if (mParentFolder == null) {
+             // should not be necessary
+             mParentFolder = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);
+         }
+         if (savedInstanceState != null) {
+             mRequestWaitingForBinder = savedInstanceState.getBoolean(KEY_WAITING_FOR_BINDER);
+         } else {
+             mRequestWaitingForBinder = false;
+         }
+         
+         createViewPager();
+     }
+     private void createViewPager() {
+         mPreviewImagePagerAdapter = new PreviewImagePagerAdapter(getSupportFragmentManager(), mParentFolder, mAccount, mStorageManager);
+         mViewPager = (ViewPager) findViewById(R.id.fragmentPager);
+         int position = mPreviewImagePagerAdapter.getFilePosition(mFile);
+         position = (position >= 0) ? position : 0;
+         mViewPager.setAdapter(mPreviewImagePagerAdapter); 
+         mViewPager.setOnPageChangeListener(this);
+         mViewPager.setCurrentItem(position);
+         if (position == 0 && !mFile.isDown()) {
+             // this is necessary because mViewPager.setCurrentItem(0) just after setting the adapter does not result in a call to #onPageSelected(0) 
+             mRequestWaitingForBinder = true;
+         }
+     }
+     
+     
+     @Override
+     public void onStart() {
+         super.onStart();
+         mDownloadConnection = new PreviewImageServiceConnection();
+         bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);
+         mUploadConnection = new PreviewImageServiceConnection();
+         bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);
+     }
+     
+     @Override
+     protected void onSaveInstanceState(Bundle outState) {
+         super.onSaveInstanceState(outState);
+         outState.putBoolean(KEY_WAITING_FOR_BINDER, mRequestWaitingForBinder);    
+     }
+     /** Defines callbacks for service binding, passed to bindService() */
+     private class PreviewImageServiceConnection implements ServiceConnection {
+         @Override
+         public void onServiceConnected(ComponentName component, IBinder service) {
+                 
+             if (component.equals(new ComponentName(PreviewImageActivity.this, FileDownloader.class))) {
+                 mDownloaderBinder = (FileDownloaderBinder) service;
+                 if (mRequestWaitingForBinder) {
+                     mRequestWaitingForBinder = false;
 -                Log.d(TAG, "Upload service connected");
++                    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, "Download service suddenly disconnected");
++                Log_OC.d(TAG, "Upload service connected");
+                 mUploaderBinder = (FileUploaderBinder) service;
+             } else {
+                 return;
+             }
+             
+         }
+         @Override
+         public void onServiceDisconnected(ComponentName component) {
+             if (component.equals(new ComponentName(PreviewImageActivity.this, FileDownloader.class))) {
 -                Log.d(TAG, "Upload 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, "requestForDownload called without binder to download service");
++                Log_OC.d(TAG, "Upload service suddenly disconnected");
+                 mUploaderBinder = null;
+             }
+         }
+     };    
+     
+     
+     @Override
+     public void onStop() {
+         super.onStop();
+         if (mDownloadConnection != null) {
+             unbindService(mDownloadConnection);
+             mDownloadConnection = null;
+         }
+         if (mUploadConnection != null) {
+             unbindService(mUploadConnection);
+             mUploadConnection = null;
+         }
+     }
+     
+     
+     @Override
+     public void onDestroy() {
+         super.onDestroy();
+     }
+     
+     
+     @Override
+     public boolean onOptionsItemSelected(MenuItem item) {
+         boolean returnValue = false;
+         
+         switch(item.getItemId()){
+         case android.R.id.home:
+             backToDisplayActivity();
+             returnValue = true;
+             break;
+         default:
+               returnValue = super.onOptionsItemSelected(item);
+         }
+         
+         return returnValue;
+     }
+     @Override
+     protected void onResume() {
+         super.onResume();
+         //Log.e(TAG, "ACTIVITY, ONRESUME");
+         mDownloadFinishReceiver = new DownloadFinishReceiver();
+         IntentFilter filter = new IntentFilter(FileDownloader.DOWNLOAD_FINISH_MESSAGE);
+         filter.addAction(FileDownloader.DOWNLOAD_ADDED_MESSAGE);
+         registerReceiver(mDownloadFinishReceiver, filter);
+     }
+     @Override
+     protected void onPostResume() {
+         //Log.e(TAG, "ACTIVITY, ONPOSTRESUME");
+         super.onPostResume();
+     }
+     
+     @Override
+     public void onPause() {
+         super.onPause();
+         unregisterReceiver(mDownloadFinishReceiver);
+         mDownloadFinishReceiver = null;
+     }
+     
+     private void backToDisplayActivity() {
+         /*
+         Intent intent = new Intent(this, FileDisplayActivity.class);
+         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+         intent.putExtra(FileDetailFragment.EXTRA_FILE, mFile);
+         intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, mAccount);
+         startActivity(intent);
+         */
+         finish();
+     }
+     
+     
+     @Override
+     protected Dialog onCreateDialog(int id) {
+         Dialog dialog = null;
+         switch (id) {
+         case DIALOG_SHORT_WAIT: {
+             ProgressDialog working_dialog = new ProgressDialog(this);
+             working_dialog.setMessage(getResources().getString(
+                     R.string.wait_a_moment));
+             working_dialog.setIndeterminate(true);
+             working_dialog.setCancelable(false);
+             dialog = working_dialog;
+             break;
+         }
+         default:
+             dialog = null;
+         }
+         return dialog;
+     }
+     
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onFileStateChanged() {
+         // nothing to do here!
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public FileDownloaderBinder getFileDownloaderBinder() {
+         return mDownloaderBinder;
+     }
+     @Override
+     public FileUploaderBinder getFileUploaderBinder() {
+         return mUploaderBinder;
+     }
+     @Override
+     public void showFragmentWithDetails(OCFile file) {
+         Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+         showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
+         showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+         showDetailsIntent.putExtra(FileDetailActivity.EXTRA_MODE, FileDetailActivity.MODE_DETAILS);
+         startActivity(showDetailsIntent);
+         int pos = mPreviewImagePagerAdapter.getFilePosition(file);
+         file = mPreviewImagePagerAdapter.getFileAt(pos);
+         
+     }
+     
+     private void requestForDownload(OCFile file) {
+         if (mDownloaderBinder == null) {
 -                    Log.d(TAG, "Download finished, but the fragment is offscreen");
++            Log_OC.d(TAG, "requestForDownload called without binder to download service");
+             
+         } else if (!mDownloaderBinder.isDownloading(mAccount, file)) {
+             Intent i = new Intent(this, FileDownloader.class);
+             i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount);
+             i.putExtra(FileDownloader.EXTRA_FILE, file);
+             startService(i);
+         }
+     }
+     /**
+      * This method will be invoked when a new page becomes selected. Animation is not necessarily complete.
+      * 
+      *  @param  Position        Position index of the new selected page
+      */
+     @Override
+     public void onPageSelected(int position) {
+         if (mDownloaderBinder == null) {
+             mRequestWaitingForBinder = true;
+             
+         } else {
+             OCFile currentFile = mPreviewImagePagerAdapter.getFileAt(position); 
+             getSupportActionBar().setTitle(currentFile.getFileName());
+             if (!currentFile.isDown()) {
+                 if (!mPreviewImagePagerAdapter.pendingErrorAt(position)) {
+                     requestForDownload(currentFile);
+                 }
+             }
+         }
+     }
+     
+     /**
+      * Called when the scroll state changes. Useful for discovering when the user begins dragging, 
+      * when the pager is automatically settling to the current page. when it is fully stopped/idle.
+      * 
+      * @param   State       The new scroll state (SCROLL_STATE_IDLE, _DRAGGING, _SETTLING
+      */
+     @Override
+     public void onPageScrollStateChanged(int state) {
+     }
+     /**
+      * This method will be invoked when the current page is scrolled, either as part of a programmatically 
+      * initiated smooth scroll or a user initiated touch scroll.
+      * 
+      * @param   position                Position index of the first page currently being displayed. 
+      *                                  Page position+1 will be visible if positionOffset is nonzero.
+      *                                  
+      * @param   positionOffset          Value from [0, 1) indicating the offset from the page at position.
+      * @param   positionOffsetPixels    Value in pixels indicating the offset from position. 
+      */
+     @Override
+     public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+     }
+     
+     /**
+      * Class waiting for broadcast events from the {@link FielDownloader} service.
+      * 
+      * Updates the UI when a download is started or finished, provided that it is relevant for the
+      * folder displayed in the gallery.
+      */
+     private class DownloadFinishReceiver extends BroadcastReceiver {
+         @Override
+         public void onReceive(Context context, Intent intent) {
+             String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
+             String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
+             if (mAccount.name.equals(accountName) && 
+                     downloadedRemotePath != null) {
+                 OCFile file = mStorageManager.getFileByPath(downloadedRemotePath);
+                 int position = mPreviewImagePagerAdapter.getFilePosition(file);
+                 boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false);
+                 //boolean isOffscreen =  Math.abs((mViewPager.getCurrentItem() - position)) <= mViewPager.getOffscreenPageLimit();
+                 
+                 if (position >= 0 && intent.getAction().equals(FileDownloader.DOWNLOAD_FINISH_MESSAGE)) {
+                     if (downloadWasFine) {
+                         mPreviewImagePagerAdapter.updateFile(position, file);   
+                         
+                     } else {
+                         mPreviewImagePagerAdapter.updateWithDownloadError(position);
+                     }
+                     mPreviewImagePagerAdapter.notifyDataSetChanged();   // will trigger the creation of new fragments
+                     
+                 } else {
++                    Log_OC.d(TAG, "Download finished, but the fragment is offscreen");
+                 }
+                 
+             }
+             removeStickyBroadcast(intent);
+         }
+     }
+     @Override
+     public boolean onTouch(View v, MotionEvent event) {
+         if (event.getAction() == MotionEvent.ACTION_UP) {
+            toggleFullScreen();
+         }
+         return true;
+     }
+     
+     private void toggleFullScreen() {
+         ActionBar actionBar = getSupportActionBar();
+         if (mFullScreen) {
+             actionBar.show();
+             
+         } else {
+             actionBar.hide();
+             
+         }
+         mFullScreen = !mFullScreen;
+     }
+     
+     
+ }
index 0000000,2f51a63..8df06bf
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,685 +1,682 @@@
 -import android.util.Log;
+ /* 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.preview;
+ import java.io.File;
+ import java.lang.ref.WeakReference;
+ import java.util.ArrayList;
+ import java.util.List;
+ import android.accounts.Account;
+ import android.annotation.SuppressLint;
+ import android.app.Activity;
+ import android.content.ActivityNotFoundException;
+ import android.content.Intent;
+ 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.FragmentStatePagerAdapter;
 -import com.owncloud.android.network.OwnCloudClientUtils;
+ import android.view.Display;
+ import android.view.LayoutInflater;
+ import android.view.View;
+ import android.view.View.OnTouchListener;
+ import android.view.ViewGroup;
+ import android.webkit.MimeTypeMap;
+ import android.widget.ImageView;
+ import android.widget.ProgressBar;
+ import android.widget.TextView;
+ import android.widget.Toast;
+ import com.actionbarsherlock.app.SherlockFragment;
+ import com.actionbarsherlock.view.Menu;
+ import com.actionbarsherlock.view.MenuInflater;
+ import com.actionbarsherlock.view.MenuItem;
+ import com.owncloud.android.datamodel.FileDataStorageManager;
+ import com.owncloud.android.datamodel.OCFile;
 -import eu.alefzero.webdav.WebdavClient;
+ import com.owncloud.android.operations.OnRemoteOperationListener;
+ import com.owncloud.android.operations.RemoteOperation;
+ import com.owncloud.android.operations.RemoteOperationResult;
+ 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;
 -            Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
+ import eu.alefzero.webdav.WebdavUtils;
+ /**
+  * This fragment shows a preview of a downloaded image.
+  * 
+  * Trying to get an instance with NULL {@link OCFile} or ownCloud {@link Account} values will produce an {@link IllegalStateException}.
+  * 
+  * If the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on instantiation too.
+  * 
+  * @author David A. Velasco
+  */
+ public class PreviewImageFragment extends SherlockFragment implements   FileFragment, 
+                                                                         OnRemoteOperationListener, 
+                                                                         ConfirmationDialogFragment.ConfirmationDialogFragmentListener {
+     public static final String EXTRA_FILE = "FILE";
+     public static final String EXTRA_ACCOUNT = "ACCOUNT";
+     private View mView;
+     private OCFile mFile;
+     private Account mAccount;
+     private FileDataStorageManager mStorageManager;
+     private ImageView mImageView;
+     private TextView mMessageView;
+     private ProgressBar mProgressWheel;
+     public Bitmap mBitmap = null;
+     
+     private Handler mHandler;
+     private RemoteOperation mLastRemoteOperation;
+     
+     private static final String TAG = PreviewImageFragment.class.getSimpleName();
+     private boolean mIgnoreFirstSavedState;
+     
+     /**
+      * Creates a fragment to preview an image.
+      * 
+      * When 'imageFile' or 'ocAccount' are null
+      * 
+      * @param imageFile                 An {@link OCFile} to preview as an image in the fragment
+      * @param ocAccount                 An ownCloud account; needed to start downloads
+      * @param ignoreFirstSavedState     Flag to work around an unexpected behaviour of {@link FragmentStatePagerAdapter}; TODO better solution 
+      */
+     public PreviewImageFragment(OCFile fileToDetail, Account ocAccount, boolean ignoreFirstSavedState) {
+         mFile = fileToDetail;
+         mAccount = ocAccount;
+         mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment
+         mIgnoreFirstSavedState = ignoreFirstSavedState;
+     }
+     
+     
+     /**
+      *  Creates an empty fragment for image previews.
+      * 
+      *  MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically (for instance, when the device is turned a aside).
+      * 
+      *  DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful construction 
+      */
+     public PreviewImageFragment() {
+         mFile = null;
+         mAccount = null;
+         mStorageManager = null;
+         mIgnoreFirstSavedState = false;
+     }
+     
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onCreate(Bundle savedInstanceState) {
+         super.onCreate(savedInstanceState);
+         mHandler = new Handler();
+         setHasOptionsMenu(true);
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public View onCreateView(LayoutInflater inflater, ViewGroup container,
+             Bundle savedInstanceState) {
+         super.onCreateView(inflater, container, savedInstanceState);
+         mView = inflater.inflate(R.layout.preview_image_fragment, container, false);
+         mImageView = (ImageView)mView.findViewById(R.id.image);
+         mImageView.setVisibility(View.GONE);
+         mView.setOnTouchListener((OnTouchListener)getActivity());   // WATCH OUT THAT CAST
+         mMessageView = (TextView)mView.findViewById(R.id.message);
+         mMessageView.setVisibility(View.GONE);
+         mProgressWheel = (ProgressBar)mView.findViewById(R.id.progressWheel);
+         mProgressWheel.setVisibility(View.VISIBLE);
+         return mView;
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onAttach(Activity activity) {
+         super.onAttach(activity);
+         if (!(activity instanceof FileFragment.ContainerActivity))
+             throw new ClassCastException(activity.toString() + " must implement " + FileFragment.ContainerActivity.class.getSimpleName());
+     }
+     
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onActivityCreated(Bundle savedInstanceState) {
+         super.onActivityCreated(savedInstanceState);
+         mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());
+         if (savedInstanceState != null) {
+             if (!mIgnoreFirstSavedState) {
+                 mFile = savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_FILE);
+                 mAccount = savedInstanceState.getParcelable(PreviewImageFragment.EXTRA_ACCOUNT);
+             } else {
+                 mIgnoreFirstSavedState = false;
+             }
+         }
+         if (mFile == null) {
+             throw new IllegalStateException("Instanced with a NULL OCFile");
+         }
+         if (mAccount == null) {
+             throw new IllegalStateException("Instanced with a NULL ownCloud Account");
+         }
+         if (!mFile.isDown()) {
+             throw new IllegalStateException("There is no local file to preview");
+         }
+     }
+         
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onSaveInstanceState(Bundle outState) {
+         super.onSaveInstanceState(outState);
+         outState.putParcelable(PreviewImageFragment.EXTRA_FILE, mFile);
+         outState.putParcelable(PreviewImageFragment.EXTRA_ACCOUNT, mAccount);
+     }
+     
+     @Override
+     public void onStart() {
+         super.onStart();
+         if (mFile != null) {
+            BitmapLoader bl = new BitmapLoader(mImageView, mMessageView, mProgressWheel);
+            bl.execute(new String[]{mFile.getStoragePath()});
+         }
+     }
+     
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+         super.onCreateOptionsMenu(menu, inflater);
+         inflater.inflate(R.menu.file_actions_menu, menu);
+         List<Integer> toHide = new ArrayList<Integer>();    
+         
+         MenuItem item = null;
+         toHide.add(R.id.action_cancel_download);
+         toHide.add(R.id.action_cancel_upload);
+         toHide.add(R.id.action_download_file);
+         toHide.add(R.id.action_rename_file);    // by now
+         for (int i : toHide) {
+             item = menu.findItem(i);
+             if (item != null) {
+                 item.setVisible(false);
+                 item.setEnabled(false);
+             }
+         }
+         
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public boolean onOptionsItemSelected(MenuItem item) {
+         switch (item.getItemId()) {
+             case R.id.action_open_file_with: {
+                 openFile();
+                 return true;
+             }
+             case R.id.action_remove_file: {
+                 removeFile();
+                 return true;
+             }
+             case R.id.action_see_details: {
+                 seeDetails();
+                 return true;
+             }
+             
+             default:
+                 return false;
+         }
+     }
+     
+     private void seeDetails() {
+         ((FileFragment.ContainerActivity)getActivity()).showFragmentWithDetails(mFile);        
+     }
+     @Override
+     public void onResume() {
+         super.onResume();
+         //Log.e(TAG, "FRAGMENT, ONRESUME");
+         /*
+         mDownloadFinishReceiver = new DownloadFinishReceiver();
+         IntentFilter filter = new IntentFilter(
+                 FileDownloader.DOWNLOAD_FINISH_MESSAGE);
+         getActivity().registerReceiver(mDownloadFinishReceiver, filter);
+         
+         mUploadFinishReceiver = new UploadFinishReceiver();
+         filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);
+         getActivity().registerReceiver(mUploadFinishReceiver, filter);
+         */
+     }
+     @Override
+     public void onPause() {
+         super.onPause();
+         /*
+         if (mVideoPreview.getVisibility() == View.VISIBLE) {
+             mSavedPlaybackPosition = mVideoPreview.getCurrentPosition();
+         }*/
+         /*
+         getActivity().unregisterReceiver(mDownloadFinishReceiver);
+         mDownloadFinishReceiver = null;
+         
+         getActivity().unregisterReceiver(mUploadFinishReceiver);
+         mUploadFinishReceiver = null;
+         */
+     }
+     @Override
+     public void onDestroy() {
+         super.onDestroy();
+         if (mBitmap != null) {
+             mBitmap.recycle();
+         }
+     }
+     
+     /**
+      * Opens the previewed image with an external application.
+      * 
+      * TODO - improve this; instead of prioritize the actions available for the MIME type in the server, 
+      * we should get a list of available apps for MIME tpye in the server and join it with the list of 
+      * available apps for the MIME type known from the file extension, to let the user choose
+      */
+     private void openFile() {
+         String storagePath = mFile.getStoragePath();
+         String encodedStoragePath = WebdavUtils.encodePath(storagePath);
+         try {
+             Intent i = new Intent(Intent.ACTION_VIEW);
+             i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype());
+             i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+             startActivity(i);
+             
+         } catch (Throwable t) {
 -                Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
++            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 {
+                 Intent i = new Intent(Intent.ACTION_VIEW);
+                 mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
+                 if (mimeType == null || !mimeType.equals(mFile.getMimetype())) {
+                     if (mimeType != null) {
+                         i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);
+                     } else {
+                         // desperate try
+                         i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*-/*");
+                     }
+                     i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+                     startActivity(i);
+                     toastIt = false;
+                 }
+                 
+             } catch (IndexOutOfBoundsException e) {
 -                Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
++                Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
+                 
+             } catch (ActivityNotFoundException e) {
 -                Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);
++                Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
+                 
+             } catch (Throwable th) {
 -            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
 -            mLastRemoteOperation.execute(wc, this, mHandler);
++                Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
+                 
+             } finally {
+                 if (toastIt) {
+                     Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();
+                 }
+             }
+             
+         }
+         finish();
+     }
+     
+     
+     /**
+      * Starts a the removal of the previewed file.
+      * 
+      * Shows a confirmation dialog. The action continues in {@link #onConfirmation(String)} , {@link #onNeutral(String)} or {@link #onCancel(String)},
+      * depending upon the user selection in the dialog. 
+      */
+     private void removeFile() {
+         ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(
+                 R.string.confirmation_remove_alert,
+                 new String[]{mFile.getFileName()},
+                 R.string.confirmation_remove_remote_and_local,
+                 R.string.confirmation_remove_local,
+                 R.string.common_cancel);
+         confDialog.setOnConfirmationListener(this);
+         confDialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
+     }
+     
+     /**
+      * Performs the removal of the previewed file, both locally and in the server.
+      */
+     @Override
+     public void onConfirmation(String callerTag) {
+         if (mStorageManager.getFileById(mFile.getFileId()) != null) {   // check that the file is still there;
+             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);
 -                //Log.d(TAG, "Image loaded - width: " + options.outWidth + ", loaded height: " + options.outHeight);
++            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
+             
+             getActivity().showDialog(PreviewImageActivity.DIALOG_SHORT_WAIT);
+         }
+     }
+     
+     
+     /**
+      * Removes the file from local storage
+      */
+     @Override
+     public void onNeutral(String callerTag) {
+         // TODO this code should be made in a secondary thread,
+         if (mFile.isDown()) {   // checks it is still there
+             File f = new File(mFile.getStoragePath());
+             f.delete();
+             mFile.setStoragePath(null);
+             mStorageManager.saveFile(mFile);
+             finish();
+         }
+     }
+     
+     /**
+      * User cancelled the removal action.
+      */
+     @Override
+     public void onCancel(String callerTag) {
+         // nothing to do here
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     public OCFile getFile(){
+         return mFile;
+     }
+     
+     /*
+     /**
+      * Use this method to signal this Activity that it shall update its view.
+      * 
+      * @param file : An {@link OCFile}
+      *-/
+     public void updateFileDetails(OCFile file, Account ocAccount) {
+         mFile = file;
+         if (ocAccount != null && ( 
+                 mStorageManager == null || 
+                 (mAccount != null && !mAccount.equals(ocAccount))
+            )) {
+             mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());
+         }
+         mAccount = ocAccount;
+         updateFileDetails(false);
+     }
+     */
+     
+     private class BitmapLoader extends AsyncTask<String, Void, Bitmap> {
+         /**
+          * Weak reference to the target {@link ImageView} where the bitmap will be loaded into.
+          * 
+          * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes.
+          */
+         private final WeakReference<ImageView> mImageViewRef;
+         /**
+          * Weak reference to the target {@link TextView} where error messages will be written.
+          * 
+          * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes.
+          */
+         private final WeakReference<TextView> mMessageViewRef;
+         
+         /**
+          * Weak reference to the target {@link Progressbar} shown while the load is in progress.
+          * 
+          * Using a weak reference will avoid memory leaks if the target ImageView is retired from memory before the load finishes.
+          */
+         private final WeakReference<ProgressBar> mProgressWheelRef;
+         
+         /**
+          * Error message to show when a load fails 
+          */
+         private int mErrorMessageId;
+         
+         
+         /**
+          * Constructor.
+          * 
+          * @param imageView     Target {@link ImageView} where the bitmap will be loaded into.
+          */
+         public BitmapLoader(ImageView imageView, TextView messageView, ProgressBar progressWheel) {
+             mImageViewRef = new WeakReference<ImageView>(imageView);
+             mMessageViewRef = new WeakReference<TextView>(messageView);
+             mProgressWheelRef = new WeakReference<ProgressBar>(progressWheel);
+         }
+         
+         
+         @SuppressWarnings("deprecation")
+         @SuppressLint({ "NewApi", "NewApi", "NewApi" }) // to avoid Lint errors since Android SDK r20
+               @Override
+         protected Bitmap doInBackground(String... params) {
+             Bitmap result = null;
+             if (params.length != 1) return result;
+             String storagePath = params[0];
+             try {
+                 // set desired options that will affect the size of the bitmap
+                 BitmapFactory.Options options = new Options();
+                 options.inScaled = true;
+                 options.inPurgeable = true;
+                 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
+                     options.inPreferQualityOverSpeed = false;
+                 }
+                 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
+                     options.inMutable = false;
+                 }
+                 // make a false load of the bitmap - just to be able to read outWidth, outHeight and outMimeType
+                 options.inJustDecodeBounds = true;
+                 BitmapFactory.decodeFile(storagePath, options);   
+                 
+                 int width = options.outWidth;
+                 int height = options.outHeight;
+                 int scale = 1;
+                 
+                 Display display = getActivity().getWindowManager().getDefaultDisplay();
+                 Point size = new Point();
+                 int screenWidth;
+                 int screenHeight;
+                 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {
+                     display.getSize(size);
+                     screenWidth = size.x;
+                     screenHeight = size.y;
+                 } else {
+                     screenWidth = display.getWidth();
+                     screenHeight = display.getHeight();
+                 }
+                 if (width > screenWidth) {
+                     // second try to scale down the image , this time depending upon the screen size 
+                     scale = (int) Math.floor((float)width / screenWidth);
+                 }
+                 if (height > screenHeight) {
+                     scale = Math.max(scale, (int) Math.floor((float)height / screenHeight));
+                 }
+                 options.inSampleSize = scale;
+                 // really load the bitmap
+                 options.inJustDecodeBounds = false; // the next decodeFile call will be real
+                 result = BitmapFactory.decodeFile(storagePath, options);
 -                    Log.e(TAG, "File could not be loaded as a bitmap: " + storagePath);
++                //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, "Out of memory occured for file " + storagePath, e);
++                    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, "Error from access to unexisting field despite protection; 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, "Unexpected error loading " + mFile.getStoragePath(), t);
++                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_OC.e(TAG, "Unexpected error loading " + mFile.getStoragePath(), t);
+                 
+             }
+             return result;
+         }
+         
+         @Override
+         protected void onPostExecute(Bitmap result) {
+             hideProgressWheel();
+             if (result != null) {
+                 showLoadedImage(result);
+             } else {
+                 showErrorMessage();
+             }
+         }
+         
+         private void showLoadedImage(Bitmap result) {
+             if (mImageViewRef != null) {
+                 final ImageView imageView = mImageViewRef.get();
+                 if (imageView != null) {
+                     imageView.setImageBitmap(result);
+                     imageView.setVisibility(View.VISIBLE);
+                     mBitmap  = result;
+                 } // else , silently finish, the fragment was destroyed
+             }
+             if (mMessageViewRef != null) {
+                 final TextView messageView = mMessageViewRef.get();
+                 if (messageView != null) {
+                     messageView.setVisibility(View.GONE);
+                 } // else , silently finish, the fragment was destroyed
+             }
+         }
+         
+         private void showErrorMessage() {
+             if (mImageViewRef != null) {
+                 final ImageView imageView = mImageViewRef.get();
+                 if (imageView != null) {
+                     // shows the default error icon
+                     imageView.setVisibility(View.VISIBLE);
+                 } // else , silently finish, the fragment was destroyed
+             }
+             if (mMessageViewRef != null) {
+                 final TextView messageView = mMessageViewRef.get();
+                 if (messageView != null) {
+                     messageView.setText(mErrorMessageId);
+                     messageView.setVisibility(View.VISIBLE);
+                 } // else , silently finish, the fragment was destroyed
+             }
+         }
+         
+         private void hideProgressWheel() {
+             if (mProgressWheelRef != null) {
+                 final ProgressBar progressWheel = mProgressWheelRef.get();
+                 if (progressWheel != null) {
+                     progressWheel.setVisibility(View.GONE);
+                 }
+             }
+         }
+         
+     }
+     /**
+      * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewImageFragment} to be previewed.
+      * 
+      * @param file      File to test if can be previewed.
+      * @return          'True' if the file can be handled by the fragment.
+      */
+     public static boolean canBePreviewed(OCFile file) {
+         return (file != null && file.isImage());
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+         if (operation.equals(mLastRemoteOperation) && operation instanceof RemoveFileOperation) {
+             onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
+         }
+     }
+     
+     private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
+         getActivity().dismissDialog(PreviewImageActivity.DIALOG_SHORT_WAIT);
+         
+         if (result.isSuccess()) {
+             Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);
+             msg.show();
+             finish();
+                 
+         } else {
+             Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); 
+             msg.show();
+             if (result.isSslRecoverableException()) {
+                 // TODO show the SSL warning dialog
+             }
+         }
+     }
+     /**
+      * Finishes the preview
+      */
+     private void finish() {
+         Activity container = getActivity();
+         container.finish();
+     }
+     
+     
+ }
index 0000000,b5945bd..a253624
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,352 +1,344 @@@
 -import java.util.ArrayList;
+ /* 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.preview;
 -import android.os.Bundle;
 -import android.os.Parcelable;
+ import java.util.HashMap;
+ import java.util.HashSet;
+ import java.util.Map;
+ import java.util.Set;
+ import java.util.Vector;
+ import android.accounts.Account;
 -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.support.v4.app.Fragment;
+ import android.support.v4.app.FragmentManager;
+ import android.support.v4.app.FragmentStatePagerAdapter;
+ import android.view.ViewGroup;
+ import com.owncloud.android.datamodel.DataStorageManager;
+ import com.owncloud.android.datamodel.OCFile;
+ import com.owncloud.android.ui.fragment.FileFragment;
+ /**
+  * Adapter class that provides Fragment instances  
+  * 
+  * @author David A. Velasco
+  */
+ //public class PreviewImagePagerAdapter extends PagerAdapter {
+ public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
+     
+     private static final String TAG = PreviewImagePagerAdapter.class.getSimpleName();
+             
+     private Vector<OCFile> mImageFiles;
+     private Account mAccount;
+     private Set<Object> mObsoleteFragments;
+     private Set<Integer> mObsoletePositions;
+     private Set<Integer> mDownloadErrors;
+     private DataStorageManager mStorageManager;
+     
+     private Map<Integer, FileFragment> mCachedFragments;
+     /*
+     private final FragmentManager mFragmentManager;
+     private FragmentTransaction mCurTransaction = null;
+     private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
+     private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
+     private Fragment mCurrentPrimaryItem = null;
+     */
+     /**
+      * Constructor.
+      * 
+      * @param fragmentManager   {@link FragmentManager} instance that will handle the {@link Fragment}s provided by the adapter. 
+      * @param parentFolder      Folder where images will be searched for.
+      * @param storageManager    Bridge to database.
+      */
+     public PreviewImagePagerAdapter(FragmentManager fragmentManager, OCFile parentFolder, Account account, DataStorageManager storageManager) {
+         super(fragmentManager);
+         
+         if (fragmentManager == null) {
+             throw new IllegalArgumentException("NULL FragmentManager instance");
+         }
+         if (parentFolder == null) {
+             throw new IllegalArgumentException("NULL parent folder");
+         } 
+         if (storageManager == null) {
+             throw new IllegalArgumentException("NULL storage manager");
+         }
+         mAccount = account;
+         mStorageManager = storageManager;
+         mImageFiles = mStorageManager.getDirectoryImages(parentFolder); 
+         mObsoleteFragments = new HashSet<Object>();
+         mObsoletePositions = new HashSet<Integer>();
+         mDownloadErrors = new HashSet<Integer>();
+         //mFragmentManager = fragmentManager;
+         mCachedFragments = new HashMap<Integer, FileFragment>();
+     }
+     
+     /**
+      * Returns the image files handled by the adapter.
+      * 
+      * @return  A vector with the image files handled by the adapter.
+      */
+     protected OCFile getFileAt(int position) {
+         return mImageFiles.get(position);
+     }
+     
+     public Fragment getItem(int i) {
+         OCFile file = mImageFiles.get(i);
+         Fragment fragment = null;
+         if (file.isDown()) {
+             fragment = new PreviewImageFragment(file, mAccount, mObsoletePositions.contains(Integer.valueOf(i)));
+             
+         } else if (mDownloadErrors.contains(Integer.valueOf(i))) {
+             fragment = new FileDownloadFragment(file, mAccount, true);
+             ((FileDownloadFragment)fragment).setError(true);
+             mDownloadErrors.remove(Integer.valueOf(i));
+             
+         } else {
+             fragment = new FileDownloadFragment(file, mAccount, mObsoletePositions.contains(Integer.valueOf(i)));
+         }
+         mObsoletePositions.remove(Integer.valueOf(i));
+         return fragment;
+     }
+     public int getFilePosition(OCFile file) {
+         return mImageFiles.indexOf(file);
+     }
+     
+     @Override
+     public int getCount() {
+         return mImageFiles.size();
+     }
+     @Override
+     public CharSequence getPageTitle(int position) {
+         return mImageFiles.get(position).getFileName();
+     }
+     
+     public void updateFile(int position, OCFile file) {
+         FileFragment fragmentToUpdate = mCachedFragments.get(Integer.valueOf(position));
+         if (fragmentToUpdate != null) {
+             mObsoleteFragments.add(fragmentToUpdate);
+         }
+         mObsoletePositions.add(Integer.valueOf(position));
+         mImageFiles.set(position, file);
+     }
+     
+     
+     public void updateWithDownloadError(int position) {
+         FileFragment fragmentToUpdate = mCachedFragments.get(Integer.valueOf(position));
+         if (fragmentToUpdate != null) {
+             mObsoleteFragments.add(fragmentToUpdate);
+         }
+         mDownloadErrors.add(Integer.valueOf(position));
+     }
+     
+     public void clearErrorAt(int position) {
+         FileFragment fragmentToUpdate = mCachedFragments.get(Integer.valueOf(position));
+         if (fragmentToUpdate != null) {
+             mObsoleteFragments.add(fragmentToUpdate);
+         }
+         mDownloadErrors.remove(Integer.valueOf(position));
+     }
+     
+     
+     @Override
+     public int getItemPosition(Object object) {
+         if (mObsoleteFragments.contains(object)) {
+             mObsoleteFragments.remove(object);
+             return POSITION_NONE;
+         }
+         return super.getItemPosition(object);
+     }
+     @Override
+     public Object instantiateItem(ViewGroup container, int position) {
+         Object fragment = super.instantiateItem(container, position);
+         mCachedFragments.put(Integer.valueOf(position), (FileFragment)fragment);
+         return fragment;
+     }
+     
+     @Override
+     public void destroyItem(ViewGroup container, int position, Object object) {
+        mCachedFragments.remove(Integer.valueOf(position));
+        super.destroyItem(container, position, object);
+     }
+     public boolean pendingErrorAt(int position) {
+         return mDownloadErrors.contains(Integer.valueOf(position));
+     }
+     
+     /* -*
+      * Called when a change in the shown pages is going to start being made.
+      * 
+      * @param   container   The containing View which is displaying this adapter's page views.
+      *- /
+     @Override
+     public void startUpdate(ViewGroup container) {
+         Log.e(TAG, "** startUpdate");
+     }
+     @Override
+     public Object instantiateItem(ViewGroup container, int position) {
+         Log.e(TAG, "** instantiateItem " + position);
+         
+         if (mFragments.size() > position) {
+             Fragment fragment = mFragments.get(position);
+             if (fragment != null) {
+                 Log.e(TAG, "** \t returning cached item");
+                 return fragment;
+             }
+         }
+         if (mCurTransaction == null) {
+             mCurTransaction = mFragmentManager.beginTransaction();
+         }
+         Fragment fragment = getItem(position);
+         if (mSavedState.size() > position) {
+             Fragment.SavedState savedState = mSavedState.get(position);
+             if (savedState != null) {
+                 // TODO WATCH OUT:
+                 // * The Fragment must currently be attached to the FragmentManager.
+                 // * A new Fragment created using this saved state must be the same class type as the Fragment it was created from.
+                 // * The saved state can not contain dependencies on other fragments -- that is it can't use putFragment(Bundle, String, Fragment) 
+                 //   to store a fragment reference                 
+                 fragment.setInitialSavedState(savedState);
+             }
+         }
+         while (mFragments.size() <= position) {
+             mFragments.add(null);
+         }
+         fragment.setMenuVisibility(false);
+         mFragments.set(position, fragment);
+         //Log.e(TAG, "** \t adding fragment at position " + position + ", containerId " + container.getId());
+         mCurTransaction.add(container.getId(), fragment);
+         return fragment;
+     }
+     @Override
+     public void destroyItem(ViewGroup container, int position, Object object) {
+         Log.e(TAG, "** destroyItem " + position);
+         Fragment fragment = (Fragment)object;
+         
+         if (mCurTransaction == null) {
+             mCurTransaction = mFragmentManager.beginTransaction();
+         }
+         Log.e(TAG, "** \t removing fragment at position " + position);
+         while (mSavedState.size() <= position) {
+             mSavedState.add(null);
+         }
+         mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment));
+         mFragments.set(position, null);
+         mCurTransaction.remove(fragment);
+     }
+     @Override
+     public void setPrimaryItem(ViewGroup container, int position, Object object) {
+         Fragment fragment = (Fragment)object;
+         if (fragment != mCurrentPrimaryItem) {
+             if (mCurrentPrimaryItem != null) {
+                 mCurrentPrimaryItem.setMenuVisibility(false);
+             }
+             if (fragment != null) {
+                 fragment.setMenuVisibility(true);
+             }
+             mCurrentPrimaryItem = fragment;
+         }
+     }
+     @Override
+     public void finishUpdate(ViewGroup container) {
+         Log.e(TAG, "** finishUpdate (start)");
+         if (mCurTransaction != null) {
+             mCurTransaction.commitAllowingStateLoss();
+             mCurTransaction = null;
+             mFragmentManager.executePendingTransactions();
+         }
+         Log.e(TAG, "** finishUpdate (end)");
+     }
+     @Override
+     public boolean isViewFromObject(View view, Object object) {
+         return ((Fragment)object).getView() == view;
+     }
+     @Override
+     public Parcelable saveState() {
+         Bundle state = null;
+         if (mSavedState.size() > 0) {
+             state = new Bundle();
+             Fragment.SavedState[] savedStates = new Fragment.SavedState[mSavedState.size()];
+             mSavedState.toArray(savedStates);
+             state.putParcelableArray("states", savedStates);
+         }
+         for (int i=0; i<mFragments.size(); i++) {
+             Fragment fragment = mFragments.get(i);
+             if (fragment != null) {
+                 if (state == null) {
+                     state = new Bundle();
+                 }
+                 String key = "f" + i;
+                 mFragmentManager.putFragment(state, key, fragment);
+             }
+         }
+         return state;
+     }
+     @Override
+     public void restoreState(Parcelable state, ClassLoader loader) {
+         if (state != null) {
+             Bundle bundle = (Bundle)state;
+             bundle.setClassLoader(loader);
+             Parcelable[] states = bundle.getParcelableArray("states");
+             mSavedState.clear();
+             mFragments.clear();
+             if (states != null) {
+                 for (int i=0; i<states.length; i++) {
+                     mSavedState.add((Fragment.SavedState)states[i]);
+                 }
+             }
+             Iterable<String> keys = bundle.keySet();
+             for (String key: keys) {
+                 if (key.startsWith("f")) {
+                     int index = Integer.parseInt(key.substring(1));
+                     Fragment f = mFragmentManager.getFragment(bundle, key);
+                     if (f != null) {
+                         while (mFragments.size() <= index) {
+                             mFragments.add(null);
+                         }
+                         f.setMenuVisibility(false);
+                         mFragments.set(index, f);
+                     } else {
+                         Log.w(TAG, "Bad fragment at key " + key);
+                     }
+                 }
+             }
+         }
+     }
+     */
+ }
index 0000000,6fbf7d6..c26d8c7
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,755 +1,752 @@@
 -import android.util.Log;
+ /* 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.preview;
+ import java.io.File;
+ import java.util.ArrayList;
+ import java.util.List;
+ import android.accounts.Account;
+ import android.app.Activity;
+ import android.app.AlertDialog;
+ import android.content.ActivityNotFoundException;
+ import android.content.ComponentName;
+ import android.content.Context;
+ import android.content.DialogInterface;
+ import android.content.Intent;
+ import android.content.ServiceConnection;
+ import android.media.MediaPlayer;
+ import android.media.MediaPlayer.OnCompletionListener;
+ import android.media.MediaPlayer.OnErrorListener;
+ import android.media.MediaPlayer.OnPreparedListener;
+ import android.net.Uri;
+ import android.os.Build;
+ import android.os.Bundle;
+ import android.os.Handler;
+ import android.os.IBinder;
+ import android.support.v4.app.FragmentTransaction;
 -import com.owncloud.android.network.OwnCloudClientUtils;
+ import android.view.LayoutInflater;
+ import android.view.MotionEvent;
+ import android.view.View;
+ import android.view.View.OnTouchListener;
+ import android.view.ViewGroup;
+ import android.webkit.MimeTypeMap;
+ import android.widget.ImageView;
+ import android.widget.Toast;
+ import android.widget.VideoView;
+ import com.actionbarsherlock.app.SherlockFragment;
+ import com.actionbarsherlock.view.Menu;
+ 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.media.MediaControlView;
+ import com.owncloud.android.media.MediaService;
+ import com.owncloud.android.media.MediaServiceBinder;
 -import eu.alefzero.webdav.WebdavClient;
+ import com.owncloud.android.operations.OnRemoteOperationListener;
+ import com.owncloud.android.operations.RemoteOperation;
+ import com.owncloud.android.operations.RemoteOperationResult;
+ import com.owncloud.android.operations.RemoveFileOperation;
+ import com.owncloud.android.ui.activity.FileDetailActivity;
+ import com.owncloud.android.ui.activity.FileDisplayActivity;
+ 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;
 -            Log.e(TAG, "onPrepared");
+ import eu.alefzero.webdav.WebdavUtils;
+ /**
+  * This fragment shows a preview of a downloaded media file (audio or video).
+  * 
+  * Trying to get an instance with NULL {@link OCFile} or ownCloud {@link Account} values will produce an {@link IllegalStateException}.
+  * 
+  * By now, if the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on instantiation too.
+  * 
+  * @author David A. Velasco
+  */
+ public class PreviewMediaFragment extends SherlockFragment implements
+         OnTouchListener , FileFragment,  
+         ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener  {
+     public static final String EXTRA_FILE = "FILE";
+     public static final String EXTRA_ACCOUNT = "ACCOUNT";
+     private static final String EXTRA_PLAY_POSITION = "PLAY_POSITION";
+     private static final String EXTRA_PLAYING = "PLAYING";
+     private View mView;
+     private OCFile mFile;
+     private Account mAccount;
+     private FileDataStorageManager mStorageManager;
+     private ImageView mImagePreview;
+     private VideoView mVideoPreview;
+     private int mSavedPlaybackPosition;
+     
+     private Handler mHandler;
+     private RemoteOperation mLastRemoteOperation;
+     
+     private MediaServiceBinder mMediaServiceBinder = null;
+     private MediaControlView mMediaController = null;
+     private MediaServiceConnection mMediaServiceConnection = null;
+     private VideoHelper mVideoHelper;
+     private boolean mAutoplay;
+     
+     private static final String TAG = PreviewMediaFragment.class.getSimpleName();
+     
+     /**
+      * Creates a fragment to preview a file.
+      * 
+      * When 'fileToDetail' or 'ocAccount' are null
+      * 
+      * @param fileToDetail      An {@link OCFile} to preview in the fragment
+      * @param ocAccount         An ownCloud account; needed to start downloads
+      */
+     public PreviewMediaFragment(OCFile fileToDetail, Account ocAccount) {
+         mFile = fileToDetail;
+         mAccount = ocAccount;
+         mSavedPlaybackPosition = 0;
+         mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment 
+         mAutoplay = true;
+     }
+     
+     
+     /**
+      *  Creates an empty fragment for previews.
+      * 
+      *  MUST BE KEPT: the system uses it when tries to reinstantiate a fragment automatically (for instance, when the device is turned a aside).
+      * 
+      *  DO NOT CALL IT: an {@link OCFile} and {@link Account} must be provided for a successful construction 
+      */
+     public PreviewMediaFragment() {
+         mFile = null;
+         mAccount = null;
+         mSavedPlaybackPosition = 0;
+         mStorageManager = null;
+         mAutoplay = true;
+     }
+     
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onCreate(Bundle savedInstanceState) {
+         super.onCreate(savedInstanceState);
+         mHandler = new Handler();
+         setHasOptionsMenu(true);
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public View onCreateView(LayoutInflater inflater, ViewGroup container,
+             Bundle savedInstanceState) {
+         super.onCreateView(inflater, container, savedInstanceState);
+         
+         mView = inflater.inflate(R.layout.file_preview, container, false);
+         
+         mImagePreview = (ImageView)mView.findViewById(R.id.image_preview);
+         mVideoPreview = (VideoView)mView.findViewById(R.id.video_preview);
+         mVideoPreview.setOnTouchListener(this);
+         
+         mMediaController = (MediaControlView)mView.findViewById(R.id.media_controller);
+         
+         return mView;
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onAttach(Activity activity) {
+         super.onAttach(activity);
+         if (!(activity instanceof FileFragment.ContainerActivity))
+             throw new ClassCastException(activity.toString() + " must implement " + FileFragment.ContainerActivity.class.getSimpleName());
+     }
+     
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onActivityCreated(Bundle savedInstanceState) {
+         super.onActivityCreated(savedInstanceState);
+         mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());
+         if (savedInstanceState != null) {
+             mFile = savedInstanceState.getParcelable(PreviewMediaFragment.EXTRA_FILE);
+             mAccount = savedInstanceState.getParcelable(PreviewMediaFragment.EXTRA_ACCOUNT);
+             mSavedPlaybackPosition = savedInstanceState.getInt(PreviewMediaFragment.EXTRA_PLAY_POSITION);
+             mAutoplay = savedInstanceState.getBoolean(PreviewMediaFragment.EXTRA_PLAYING);
+             
+         }
+         if (mFile == null) {
+             throw new IllegalStateException("Instanced with a NULL OCFile");
+         }
+         if (mAccount == null) {
+             throw new IllegalStateException("Instanced with a NULL ownCloud Account");
+         }
+         if (!mFile.isDown()) {
+             throw new IllegalStateException("There is no local file to preview");
+         }
+         if (mFile.isVideo()) {
+             mVideoPreview.setVisibility(View.VISIBLE);
+             mImagePreview.setVisibility(View.GONE);
+             prepareVideo();
+             
+         } else {
+             mVideoPreview.setVisibility(View.GONE);
+             mImagePreview.setVisibility(View.VISIBLE);
+         }
+         
+     }
+         
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onSaveInstanceState(Bundle outState) {
+         super.onSaveInstanceState(outState);
+         outState.putParcelable(PreviewMediaFragment.EXTRA_FILE, mFile);
+         outState.putParcelable(PreviewMediaFragment.EXTRA_ACCOUNT, mAccount);
+         
+         if (mFile.isVideo()) {
+             mSavedPlaybackPosition = mVideoPreview.getCurrentPosition();
+             mAutoplay = mVideoPreview.isPlaying();
+             outState.putInt(PreviewMediaFragment.EXTRA_PLAY_POSITION , mSavedPlaybackPosition);
+             outState.putBoolean(PreviewMediaFragment.EXTRA_PLAYING , mAutoplay);
+         } else {
+             outState.putInt(PreviewMediaFragment.EXTRA_PLAY_POSITION , mMediaServiceBinder.getCurrentPosition());
+             outState.putBoolean(PreviewMediaFragment.EXTRA_PLAYING , mMediaServiceBinder.isPlaying());
+         }
+     }
+     
+     @Override
+     public void onStart() {
+         super.onStart();
+         if (mFile != null) {
+            if (mFile.isAudio()) {
+                bindMediaService();
+                
+            } else if (mFile.isVideo()) {
+                stopAudio();
+                playVideo(); 
+            }
+         }
+     }
+     
+     
+     private void stopAudio() {
+         Intent i = new Intent(getSherlockActivity(), MediaService.class);
+         i.setAction(MediaService.ACTION_STOP_ALL);
+         getSherlockActivity().startService(i);
+     }
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+         super.onCreateOptionsMenu(menu, inflater);
+         inflater.inflate(R.menu.file_actions_menu, menu);
+         List<Integer> toHide = new ArrayList<Integer>();    
+         
+         MenuItem item = null;
+         toHide.add(R.id.action_cancel_download);
+         toHide.add(R.id.action_cancel_upload);
+         toHide.add(R.id.action_download_file);
+         toHide.add(R.id.action_rename_file);    // by now
+         for (int i : toHide) {
+             item = menu.findItem(i);
+             if (item != null) {
+                 item.setVisible(false);
+                 item.setEnabled(false);
+             }
+         }
+         
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public boolean onOptionsItemSelected(MenuItem item) {
+         switch (item.getItemId()) {
+             case R.id.action_open_file_with: {
+                 openFile();
+                 return true;
+             }
+             case R.id.action_remove_file: {
+                 removeFile();
+                 return true;
+             }
+             case R.id.action_see_details: {
+                 seeDetails();
+                 return true;
+             }
+             
+             default:
+                 return false;
+         }
+     }
+     
+     private void seeDetails() {
+         stopPreview(false);
+         ((FileFragment.ContainerActivity)getActivity()).showFragmentWithDetails(mFile);        
+     }
+     private void prepareVideo() {
+         // create helper to get more control on the playback
+         mVideoHelper = new VideoHelper();
+         mVideoPreview.setOnPreparedListener(mVideoHelper);
+         mVideoPreview.setOnCompletionListener(mVideoHelper);
+         mVideoPreview.setOnErrorListener(mVideoHelper);
+     }
+     
+     private void playVideo() {
+         // create and prepare control panel for the user
+         mMediaController.setMediaPlayer(mVideoPreview);
+         
+         // load the video file in the video player ; when done, VideoHelper#onPrepared() will be called
+         mVideoPreview.setVideoPath(mFile.getStoragePath()); 
+     }
+     
+     private class VideoHelper implements OnCompletionListener, OnPreparedListener, OnErrorListener {
+         
+         /** 
+          * Called when the file is ready to be played.
+          * 
+          * Just starts the playback.
+          * 
+          * @param   mp    {@link MediaPlayer} instance performing the playback.
+          */
+         @Override
+         public void onPrepared(MediaPlayer vp) {
 -            Log.e(TAG, "completed");
++            Log_OC.e(TAG, "onPrepared");
+             mVideoPreview.seekTo(mSavedPlaybackPosition);
+             if (mAutoplay) { 
+                 mVideoPreview.start();
+             }
+             mMediaController.setEnabled(true);
+             mMediaController.updatePausePlay();
+         }
+         
+         
+         /**
+          * Called when the file is finished playing.
+          *  
+          * Finishes the activity.
+          * 
+          * @param   mp    {@link MediaPlayer} instance performing the playback.
+          */
+         @Override
+         public void onCompletion(MediaPlayer  mp) {
 -            Log.d(TAG, "Unbinding from MediaService ...");
++            Log_OC.e(TAG, "completed");
+             if (mp != null) {
+                 mVideoPreview.seekTo(0);
+                 // next lines are necessary to work around undesired video loops
+                 if (Build.VERSION.SDK_INT == Build.VERSION_CODES.GINGERBREAD) {
+                     mVideoPreview.pause();   
+                     
+                 } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.GINGERBREAD_MR1) {
+                     // mVideePreview.pause() is not enough
+                     
+                     mMediaController.setEnabled(false);
+                     mVideoPreview.stopPlayback();
+                     mAutoplay = false;
+                     mSavedPlaybackPosition = 0;
+                     mVideoPreview.setVideoPath(mFile.getStoragePath());
+                 }
+             } // else : called from onError()
+             mMediaController.updatePausePlay();
+         }
+         
+         
+         /**
+          * Called when an error in playback occurs.
+          * 
+          * @param   mp      {@link MediaPlayer} instance performing the playback.
+          * @param   what    Type of error
+          * @param   extra   Extra code specific to the error
+          */
+         @Override
+         public boolean onError(MediaPlayer mp, int what, int extra) {
+             if (mVideoPreview.getWindowToken() != null) {
+                 String message = MediaService.getMessageForMediaError(getActivity(), what, extra);
+                 new AlertDialog.Builder(getActivity())
+                         .setMessage(message)
+                         .setPositiveButton(android.R.string.VideoView_error_button,
+                                 new DialogInterface.OnClickListener() {
+                                     public void onClick(DialogInterface dialog, int whichButton) {
+                                         dialog.dismiss();
+                                         VideoHelper.this.onCompletion(null);
+                                     }
+                                 })
+                         .setCancelable(false)
+                         .show();
+             }
+             return true;
+         }
+         
+     }
+     
+     @Override
+     public void onStop() {
+         super.onStop();
+         
+         if (mMediaServiceConnection != null) {
 -            Log.d(TAG, "starting playback of " + mFile.getStoragePath());
++            Log_OC.d(TAG, "Unbinding from MediaService ...");
+             if (mMediaServiceBinder != null && mMediaController != null) {
+                 mMediaServiceBinder.unregisterMediaController(mMediaController);
+             }
+             getActivity().unbindService(mMediaServiceConnection);
+             mMediaServiceConnection = null;
+             mMediaServiceBinder = null;
+         }
+     }
+     
+     @Override
+     public boolean onTouch(View v, MotionEvent event) {
+         if (event.getAction() == MotionEvent.ACTION_DOWN && v == mVideoPreview) {
+             startFullScreenVideo();
+             return true;        
+         }
+         return false;
+     }
+     
+     private void startFullScreenVideo() {
+         Intent i = new Intent(getActivity(), PreviewVideoActivity.class);
+         i.putExtra(PreviewVideoActivity.EXTRA_ACCOUNT, mAccount);
+         i.putExtra(PreviewVideoActivity.EXTRA_FILE, mFile);
+         i.putExtra(PreviewVideoActivity.EXTRA_AUTOPLAY, mVideoPreview.isPlaying());
+         mVideoPreview.pause();
+         i.putExtra(PreviewVideoActivity.EXTRA_START_POSITION, mVideoPreview.getCurrentPosition());
+         startActivityForResult(i, 0);
+     }
+     
+     @Override
+     public void onActivityResult (int requestCode, int resultCode, Intent data) {
+         super.onActivityResult(requestCode, resultCode, data);
+         if (resultCode == Activity.RESULT_OK) {
+             mSavedPlaybackPosition = data.getExtras().getInt(PreviewVideoActivity.EXTRA_START_POSITION);
+             mAutoplay = data.getExtras().getBoolean(PreviewVideoActivity.EXTRA_AUTOPLAY); 
+         }
+     }
+     
+     private void playAudio() {
+         if (!mMediaServiceBinder.isPlaying(mFile)) {
 -        Log.d(TAG, "Binding to MediaService...");
++            Log_OC.d(TAG, "starting playback of " + mFile.getStoragePath());
+             mMediaServiceBinder.start(mAccount, mFile, mAutoplay, mSavedPlaybackPosition);
+             
+         } else {
+             if (!mMediaServiceBinder.isPlaying() && mAutoplay) {
+                 mMediaServiceBinder.start();
+                 mMediaController.updatePausePlay();
+             }
+         }
+     }
+     private void bindMediaService() {
 -                Log.d(TAG, "Media service connected");
++        Log_OC.d(TAG, "Binding to MediaService...");
+         if (mMediaServiceConnection == null) {
+             mMediaServiceConnection = new MediaServiceConnection();
+         }
+         getActivity().bindService(  new Intent(getActivity(), 
+                                     MediaService.class),
+                                     mMediaServiceConnection, 
+                                     Context.BIND_AUTO_CREATE);
+             // follow the flow in MediaServiceConnection#onServiceConnected(...)
+     }
+     
+     /** Defines callbacks for service binding, passed to bindService() */
+     private class MediaServiceConnection implements ServiceConnection {
+         @Override
+         public void onServiceConnected(ComponentName component, IBinder service) {
+             if (component.equals(new ComponentName(getActivity(), MediaService.class))) {
 -                    Log.d(TAG, "Successfully bound to MediaService, MediaController ready");
++                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.e(TAG, "Unexpected response from MediaService while binding");
++                    Log_OC.d(TAG, "Successfully bound to MediaService, MediaController ready");
+                     
+                 } else {
 -                Log.e(TAG, "Media service suddenly disconnected");
++                    Log_OC.e(TAG, "Unexpected response from MediaService while binding");
+                 }
+             }
+         }
+         private void prepareMediaController() {
+             mMediaServiceBinder.registerMediaController(mMediaController);
+             if (mMediaController != null) {
+                 mMediaController.setMediaPlayer(mMediaServiceBinder);
+                 mMediaController.setEnabled(true);
+                 mMediaController.updatePausePlay();
+             }
+         }
+         @Override
+         public void onServiceDisconnected(ComponentName component) {
+             if (component.equals(new ComponentName(getActivity(), MediaService.class))) {
 -            Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
++                Log_OC.e(TAG, "Media service suddenly disconnected");
+                 if (mMediaController != null) {
+                     mMediaController.setMediaPlayer(null);
+                 } else {
+                     Toast.makeText(getActivity(), "No media controller to release when disconnected from media service", Toast.LENGTH_SHORT).show();
+                 }
+                 mMediaServiceBinder = null;
+                 mMediaServiceConnection = null;
+             }
+         }
+     }    
+     
+     /**
+      * Opens the previewed file with an external application.
+      * 
+      * TODO - improve this; instead of prioritize the actions available for the MIME type in the server, 
+      * we should get a list of available apps for MIME tpye in the server and join it with the list of 
+      * available apps for the MIME type known from the file extension, to let the user choose
+      */
+     private void openFile() {
+         stopPreview(true);
+         String storagePath = mFile.getStoragePath();
+         String encodedStoragePath = WebdavUtils.encodePath(storagePath);
+         try {
+             Intent i = new Intent(Intent.ACTION_VIEW);
+             i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype());
+             i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+             startActivity(i);
+             
+         } catch (Throwable t) {
 -                Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
++            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 {
+                 Intent i = new Intent(Intent.ACTION_VIEW);
+                 mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
+                 if (mimeType == null || !mimeType.equals(mFile.getMimetype())) {
+                     if (mimeType != null) {
+                         i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);
+                     } else {
+                         // desperate try
+                         i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*-/*");
+                     }
+                     i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+                     startActivity(i);
+                     toastIt = false;
+                 }
+                 
+             } catch (IndexOutOfBoundsException e) {
 -                Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
++                Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
+                 
+             } catch (ActivityNotFoundException e) {
 -                Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);
++                Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
+                 
+             } catch (Throwable th) {
 -            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
 -            mLastRemoteOperation.execute(wc, this, mHandler);
++                Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
+                 
+             } finally {
+                 if (toastIt) {
+                     Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();
+                 }
+             }
+             
+         }
+         finish();
+     }
+     
+     /**
+      * Starts a the removal of the previewed file.
+      * 
+      * Shows a confirmation dialog. The action continues in {@link #onConfirmation(String)} , {@link #onNeutral(String)} or {@link #onCancel(String)},
+      * depending upon the user selection in the dialog. 
+      */
+     private void removeFile() {
+         ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(
+                 R.string.confirmation_remove_alert,
+                 new String[]{mFile.getFileName()},
+                 R.string.confirmation_remove_remote_and_local,
+                 R.string.confirmation_remove_local,
+                 R.string.common_cancel);
+         confDialog.setOnConfirmationListener(this);
+         confDialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
+     }
+     
+     /**
+      * Performs the removal of the previewed file, both locally and in the server.
+      */
+     @Override
+     public void onConfirmation(String callerTag) {
+         if (mStorageManager.getFileById(mFile.getFileId()) != null) {   // check that the file is still there;
+             stopPreview(true);
+             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);
++            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
+             
+             boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
+             getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
+         }
+     }
+     
+     
+     /**
+      * Removes the file from local storage
+      */
+     @Override
+     public void onNeutral(String callerTag) {
+         // TODO this code should be made in a secondary thread,
+         if (mFile.isDown()) {   // checks it is still there
+             stopPreview(true);
+             File f = new File(mFile.getStoragePath());
+             f.delete();
+             mFile.setStoragePath(null);
+             mStorageManager.saveFile(mFile);
+             finish();
+         }
+     }
+     
+     /**
+      * User cancelled the removal action.
+      */
+     @Override
+     public void onCancel(String callerTag) {
+         // nothing to do here
+     }
+     
+     /**
+      * {@inheritDoc}
+      */
+     public OCFile getFile(){
+         return mFile;
+     }
+     
+     /*
+     /**
+      * Use this method to signal this Activity that it shall update its view.
+      * 
+      * @param file : An {@link OCFile}
+      *-/
+     public void updateFileDetails(OCFile file, Account ocAccount) {
+         mFile = file;
+         if (ocAccount != null && ( 
+                 mStorageManager == null || 
+                 (mAccount != null && !mAccount.equals(ocAccount))
+            )) {
+             mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());
+         }
+         mAccount = ocAccount;
+         updateFileDetails(false);
+     }
+     */
+     
+     /**
+      * Helper method to test if an {@link OCFile} can be passed to a {@link PreviewMediaFragment} to be previewed.
+      * 
+      * @param file      File to test if can be previewed.
+      * @return          'True' if the file can be handled by the fragment.
+      */
+     public static boolean canBePreviewed(OCFile file) {
+         return (file != null && (file.isAudio() || file.isVideo()));
+     }
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+         if (operation.equals(mLastRemoteOperation)) {
+             if (operation instanceof RemoveFileOperation) {
+                 onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
+             }
+         }
+     }
+     
+     private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
+         boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
+         getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
+         
+         if (result.isSuccess()) {
+             Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);
+             msg.show();
+             finish();
+                 
+         } else {
+             Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); 
+             msg.show();
+             if (result.isSslRecoverableException()) {
+                 // TODO show the SSL warning dialog
+             }
+         }
+     }
+     private void stopPreview(boolean stopAudio) {
+         if (mFile.isAudio() && stopAudio) {
+             mMediaServiceBinder.pause();
+             
+         } else if (mFile.isVideo()) {
+             mVideoPreview.stopPlayback();
+         }
+     }
+     /**
+      * Finishes the preview
+      */
+     private void finish() {
+         Activity container = getActivity();
+         if (container instanceof FileDisplayActivity) {
+             // double pane
+             FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
+             transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment
+             transaction.commit();
+             ((FileFragment.ContainerActivity)container).onFileStateChanged();
+         } else {
+             container.finish();
+         }
+     }
+     
+ }
index 0000000,c335bf4..3cbff7d
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,282 +1,282 @@@
 -import android.util.Log;
+ /* 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.preview;
+ import android.accounts.Account;
+ import android.app.Activity;
+ import android.app.AlertDialog;
+ import android.content.DialogInterface;
+ import android.content.Intent;
+ import android.media.MediaPlayer;
+ import android.media.MediaPlayer.OnCompletionListener;
+ import android.media.MediaPlayer.OnErrorListener;
+ import android.media.MediaPlayer.OnPreparedListener;
+ import android.net.Uri;
+ import android.os.Bundle;
 -        Log.e(TAG, "ACTIVITY\t\tonCreate");
+ 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;
+ /**
+  *  Activity implementing a basic video player.
+  * 
+  *  Used as an utility to preview video files contained in an ownCloud account.
+  *  
+  *  Currently, it always plays in landscape mode, full screen. When the playback ends,
+  *  the activity is finished. 
+  *  
+  *  @author David A. Velasco
+  */
+ public class PreviewVideoActivity extends Activity implements OnCompletionListener, OnPreparedListener, OnErrorListener {
+     /** Key to receive an {@link OCFile} to play as an extra value in an {@link Intent} */
+     public static final String EXTRA_FILE = "FILE";
+     
+     /** Key to receive the ownCloud {@link Account} where the file to play is saved as an extra value in an {@link Intent} */
+     public static final String EXTRA_ACCOUNT = "ACCOUNT";
+     
+     /** Key to receive a flag signaling if the video should be started immediately */
+     public static final String EXTRA_AUTOPLAY = "AUTOPLAY";
+     
+     /** Key to receive the position of the playback where the video should be put at start */
+     public static final String EXTRA_START_POSITION = "START_POSITION";
+     
+     private static final String TAG = PreviewVideoActivity.class.getSimpleName();
+     private OCFile mFile;                       // video file to play
+     private Account mAccount;                   // ownCloud account holding mFile
+     private int mSavedPlaybackPosition;         // in the unit time handled by MediaPlayer.getCurrentPosition()
+     private boolean mAutoplay;                  // when 'true', the playback starts immediately with the activity
+     private VideoView mVideoPlayer;             // view to play the file; both performs and show the playback
+     private MediaController mMediaController;   // panel control used by the user to control the playback
+           
+     /** 
+      *  Called when the activity is first created.
+      *  
+      *  Searches for an {@link OCFile} and ownCloud {@link Account} holding it in the starting {@link Intent}.
+      *  
+      *  The {@link Account} is unnecessary if the file is downloaded; else, the {@link Account} is used to 
+      *  try to stream the remote file - TODO get the streaming works
+      * 
+      *  {@inheritDoc}
+      */
+     @Override
+     public void onCreate(Bundle savedInstanceState) {
+         super.onCreate(savedInstanceState);
 -        Log.e(TAG, "ACTIVITY\t\tonSaveInstanceState");
++        Log_OC.e(TAG, "ACTIVITY\t\tonCreate");
+         
+         setContentView(R.layout.video_layout);
+     
+         if (savedInstanceState == null) {
+             Bundle extras = getIntent().getExtras();
+             mFile = extras.getParcelable(EXTRA_FILE);
+             mAccount = extras.getParcelable(EXTRA_ACCOUNT);
+             mSavedPlaybackPosition = extras.getInt(EXTRA_START_POSITION);
+             mAutoplay = extras.getBoolean(EXTRA_AUTOPLAY);
+             
+         } else {
+             mFile = savedInstanceState.getParcelable(EXTRA_FILE);
+             mAccount = savedInstanceState.getParcelable(EXTRA_ACCOUNT);
+             mSavedPlaybackPosition = savedInstanceState.getInt(EXTRA_START_POSITION);
+             mAutoplay = savedInstanceState.getBoolean(EXTRA_AUTOPLAY);
+         }
+           
+         mVideoPlayer = (VideoView) findViewById(R.id.videoPlayer);
+         // set listeners to get more contol on the playback
+         mVideoPlayer.setOnPreparedListener(this);
+         mVideoPlayer.setOnCompletionListener(this);
+         mVideoPlayer.setOnErrorListener(this);
+           
+         // keep the screen on while the playback is performed (prevents screen off by battery save)
+         mVideoPlayer.setKeepScreenOn(true);
+         
+         if (mFile != null) {
+             if (mFile.isDown()) {
+                 mVideoPlayer.setVideoPath(mFile.getStoragePath());
+                 
+             } else if (mAccount != null) {
+                 // not working now
+                 String url = AccountUtils.constructFullURLForAccount(this, mAccount) + mFile.getRemotePath();
+                 mVideoPlayer.setVideoURI(Uri.parse(url));
+                 
+             } else {
+                 onError(null, MediaService.OC_MEDIA_ERROR, R.string.media_err_no_account);
+             }
+             
+             // create and prepare control panel for the user
+             mMediaController = new MediaController(this);
+             mMediaController.setMediaPlayer(mVideoPlayer);
+             mMediaController.setAnchorView(mVideoPlayer);
+             mVideoPlayer.setMediaController(mMediaController);
+             
+         } else {
+             onError(null, MediaService.OC_MEDIA_ERROR, R.string.media_err_nothing_to_play);
+         }
+     }    
+     
+     
+     /**
+      * {@inheritDoc}
+      */
+     @Override
+     public void onSaveInstanceState(Bundle outState) {
+         super.onSaveInstanceState(outState);
 -        Log.e(TAG, "ACTIVTIY\t\tonBackPressed");
++        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());
+         outState.putBoolean(PreviewVideoActivity.EXTRA_AUTOPLAY , mVideoPlayer.isPlaying());
+     }
+     
+     @Override
+     public void onBackPressed() {
 -        Log.e(TAG, "ACTIVTIY\t\tonResume");
++        Log_OC.e(TAG, "ACTIVTIY\t\tonBackPressed");
+         Intent i = new Intent();
+         i.putExtra(EXTRA_AUTOPLAY, mVideoPlayer.isPlaying());
+         i.putExtra(EXTRA_START_POSITION, mVideoPlayer.getCurrentPosition());
+         setResult(RESULT_OK, i);
+         super.onBackPressed();
+     }
+     
+     @Override
+     public void onResume() {
+         super.onResume();
 -        Log.e(TAG, "ACTIVTIY\t\tonStart");
++        Log_OC.e(TAG, "ACTIVTIY\t\tonResume");
+     }
+     
+     @Override
+     public void onStart() {
+         super.onStart();
 -        Log.e(TAG, "ACTIVITY\t\tonDestroy");
++        Log_OC.e(TAG, "ACTIVTIY\t\tonStart");
+     }
+     
+     @Override
+     public void onDestroy() {
+         super.onDestroy();
 -        Log.e(TAG, "ACTIVTIY\t\tonStop");
++        Log_OC.e(TAG, "ACTIVITY\t\tonDestroy");
+     }
+     
+     @Override
+     public void onStop() {
+         super.onStop();
 -        Log.e(TAG, "ACTIVTIY\t\tonPause");
++        Log_OC.e(TAG, "ACTIVTIY\t\tonStop");
+     }
+     
+     
+     @Override
+     public void onPause() {
+         super.onPause();
 -        Log.e(TAG, "ACTIVITY\t\tonPrepare");
++        Log_OC.e(TAG, "ACTIVTIY\t\tonPause");
+     }
+     
+     
+     /** 
+      * Called when the file is ready to be played.
+      * 
+      * Just starts the playback.
+      * 
+      * @param   mp    {@link MediaPlayer} instance performing the playback.
+      */
+     @Override
+     public void onPrepared(MediaPlayer mp) {
 -        Log.e(TAG, "Error in video playback, what = " + what + ", extra = " + extra);
++        Log_OC.e(TAG, "ACTIVITY\t\tonPrepare");
+         mVideoPlayer.seekTo(mSavedPlaybackPosition);
+         if (mAutoplay) { 
+             mVideoPlayer.start();
+         }
+         mMediaController.show(5000);  
+     }
+     
+     
+     /**
+      * Called when the file is finished playing.
+      *  
+      * Rewinds the video
+      * 
+      * @param   mp    {@link MediaPlayer} instance performing the playback.
+      */
+     @Override
+     public void onCompletion(MediaPlayer  mp) {
+         mVideoPlayer.seekTo(0);
+     }
+     
+     
+     /**
+      * Called when an error in playback occurs.
+      * 
+      * @param   mp      {@link MediaPlayer} instance performing the playback.
+      * @param   what    Type of error
+      * @param   extra   Extra code specific to the error
+      */
+     @Override
+     public boolean onError(MediaPlayer mp, int what, int extra) {
++        Log_OC.e(TAG, "Error in video playback, what = " + what + ", extra = " + extra);
+         
+         if (mMediaController != null) {
+             mMediaController.hide();
+         }
+         
+         if (mVideoPlayer.getWindowToken() != null) {
+             String message = MediaService.getMessageForMediaError(this, what, extra);
+             new AlertDialog.Builder(this)
+                     .setMessage(message)
+                     .setPositiveButton(android.R.string.VideoView_error_button,
+                             new DialogInterface.OnClickListener() {
+                                 public void onClick(DialogInterface dialog, int whichButton) {
+                                     PreviewVideoActivity.this.onCompletion(null);
+                                 }
+                             })
+                     .setCancelable(false)
+                     .show();
+         }
+         return true;
+     }
+     
+     
+     /**  
+      * Screen touches trigger the appearance of the control panel for a limited time.
+      *
+      * {@inheritDoc}
+      */
+     @Override
+     public boolean onTouchEvent (MotionEvent ev){ 
+         /*if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+             if (mMediaController.isShowing()) {
+                 mMediaController.hide();
+             } else {
+                 mMediaController.show(MediaService.MEDIA_CONTROL_SHORT_LIFE);
+             }
+             return true;        
+         } else {
+             return false;
+         }*/
+         return false;
+     }
+ }
@@@ -23,10 -24,11 +24,10 @@@ 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;
  
  /**
   * Static methods to help in access to local file system.
   * 
- /* ownCloud Android client application\r
-  *   Copyright (C) 2011  Bartek Przybylski\r
-  *   Copyright (C) 2012-2013 ownCloud Inc.\r
-  *\r
-  *   This program is free software: you can redistribute it and/or modify\r
-  *   it under the terms of the GNU General Public License as published by\r
-  *   the Free Software Foundation, either version 2 of the License, or\r
-  *   (at your option) any later version.\r
-  *\r
-  *   This program is distributed in the hope that it will be useful,\r
-  *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-  *   GNU General Public License for more details.\r
-  *\r
-  *   You should have received a copy of the GNU General Public License\r
-  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
-  *\r
-  */\r
- package eu.alefzero.webdav;\r
\r
- import java.io.BufferedInputStream;\r
- import java.io.File;\r
- import java.io.FileOutputStream;\r
- import java.io.IOException;\r
- import java.io.InputStream;\r
- import java.util.ArrayList;\r
- import java.util.List;\r
\r
- import org.apache.commons.httpclient.Credentials;\r
- import org.apache.commons.httpclient.HostConfiguration;\r
- import org.apache.commons.httpclient.HttpClient;\r
- import org.apache.commons.httpclient.HttpConnectionManager;\r
- import org.apache.commons.httpclient.HttpException;\r
- import org.apache.commons.httpclient.HttpMethod;\r
- import org.apache.commons.httpclient.HttpMethodBase;\r
- import org.apache.commons.httpclient.HttpState;\r
- import org.apache.commons.httpclient.HttpVersion;\r
- import org.apache.commons.httpclient.UsernamePasswordCredentials;\r
- import org.apache.commons.httpclient.auth.AuthPolicy;\r
- import org.apache.commons.httpclient.auth.AuthScope;\r
- import org.apache.commons.httpclient.methods.GetMethod;\r
- import org.apache.commons.httpclient.methods.HeadMethod;\r
- import org.apache.commons.httpclient.methods.PutMethod;\r
- import org.apache.commons.httpclient.params.HttpMethodParams;\r
- import org.apache.http.HttpStatus;\r
- import org.apache.http.params.CoreProtocolPNames;\r
- import org.apache.jackrabbit.webdav.client.methods.DavMethod;\r
- import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;\r
\r
- import com.owncloud.android.network.BearerAuthScheme;\r
- import com.owncloud.android.network.BearerCredentials;\r
\r
- import android.net.Uri;\r
- import android.util.Log;\r
\r
- public class WebdavClient extends HttpClient {\r
-     private Uri mUri;\r
-     private Credentials mCredentials;\r
-     final private static String TAG = "WebdavClient";\r
-     private static final String USER_AGENT = "Android-ownCloud";\r
-     \r
-     private OnDatatransferProgressListener mDataTransferListener;\r
-     static private byte[] sExhaustBuffer = new byte[1024];\r
-     \r
-     /**\r
-      * Constructor\r
-      */\r
-     public WebdavClient(HttpConnectionManager connectionMgr) {\r
-         super(connectionMgr);\r
-         Log.d(TAG, "Creating WebdavClient");\r
-         getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT);\r
-         getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);\r
-     }\r
\r
-     public void setBearerCredentials(String accessToken) {\r
-         AuthPolicy.registerAuthScheme(BearerAuthScheme.AUTH_POLICY, BearerAuthScheme.class);\r
-         \r
-         List<String> authPrefs = new ArrayList<String>(1);\r
-         authPrefs.add(BearerAuthScheme.AUTH_POLICY);\r
-         getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);        \r
-         \r
-         mCredentials = new BearerCredentials(accessToken);\r
-         getState().setCredentials(AuthScope.ANY, mCredentials);\r
-     }\r
\r
-     public void setBasicCredentials(String username, String password) {\r
-         List<String> authPrefs = new ArrayList<String>(1);\r
-         authPrefs.add(AuthPolicy.BASIC);\r
-         getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);        \r
-         \r
-         getParams().setAuthenticationPreemptive(true);\r
-         mCredentials = new UsernamePasswordCredentials(username, password);\r
-         getState().setCredentials(AuthScope.ANY, mCredentials);\r
-     }\r
-     \r
-     \r
-     /**\r
-      * Downloads a file in remoteFilepath to the local targetPath.\r
-      * \r
-      * @param remoteFilepath    Path to the file in the remote server, URL DECODED. \r
-      * @param targetFile        Local path to save the downloaded file.\r
-      * @return                  'True' when the file is successfully downloaded.\r
-      */\r
-     public boolean downloadFile(String remoteFilePath, File targetFile) {\r
-         boolean ret = false;\r
-         GetMethod get = new GetMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath));\r
\r
-         try {\r
-             int status = executeMethod(get);\r
-             if (status == HttpStatus.SC_OK) {\r
-                 targetFile.createNewFile();\r
-                 BufferedInputStream bis = new BufferedInputStream(\r
-                         get.getResponseBodyAsStream());\r
-                 FileOutputStream fos = new FileOutputStream(targetFile);\r
\r
-                 byte[] bytes = new byte[4096];\r
-                 int readResult;\r
-                 while ((readResult = bis.read(bytes)) != -1) {\r
-                     if (mDataTransferListener != null)\r
-                         mDataTransferListener.onTransferProgress(readResult);\r
-                     fos.write(bytes, 0, readResult);\r
-                 }\r
-                 fos.close();\r
-                 ret = true;\r
-             } else {\r
-                 exhaustResponse(get.getResponseBodyAsStream());\r
-             }\r
-             Log.e(TAG, "Download of " + remoteFilePath + " to " + targetFile + " finished with HTTP status " + status + (!ret?"(FAIL)":""));\r
-         } catch (Exception e) {\r
-             logException(e, "dowloading " + remoteFilePath);\r
-             \r
-         } finally {\r
-             if (!ret && targetFile.exists()) {\r
-                 targetFile.delete();\r
-             }\r
-             get.releaseConnection();    // let the connection available for other methods\r
-         }\r
-         return ret;\r
-     }\r
-     \r
-     /**\r
-      * Deletes a remote file via webdav\r
-      * @param remoteFilePath       Remote file path of the file to delete, in URL DECODED format.\r
-      * @return\r
-      */\r
-     public boolean deleteFile(String remoteFilePath) {\r
-         boolean ret = false;\r
-         DavMethod delete = new DeleteMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath));\r
-         try {\r
-             int status = executeMethod(delete);\r
-             ret = (status == HttpStatus.SC_OK || status == HttpStatus.SC_ACCEPTED || status == HttpStatus.SC_NO_CONTENT);\r
-             exhaustResponse(delete.getResponseBodyAsStream());\r
-             \r
-             Log.e(TAG, "DELETE of " + remoteFilePath + " finished with HTTP status " + status +  (!ret?"(FAIL)":""));\r
-             \r
-         } catch (Exception e) {\r
-             logException(e, "deleting " + remoteFilePath);\r
-             \r
-         } finally {\r
-             delete.releaseConnection();    // let the connection available for other methods\r
-         }\r
-         return ret;\r
-     }\r
\r
-     \r
-     public void setDataTransferProgressListener(OnDatatransferProgressListener listener) {\r
-         mDataTransferListener = listener;\r
-     }\r
-     \r
-     /**\r
-      * Creates or update a file in the remote server with the contents of a local file.\r
-      * \r
-      * @param localFile         Path to the local file to upload.\r
-      * @param remoteTarget      Remote path to the file to create or update, URL DECODED\r
-      * @param contentType       MIME type of the file.\r
-      * @return                  Status HTTP code returned by the server.\r
-      * @throws IOException      When a transport error that could not be recovered occurred while uploading the file to the server.\r
-      * @throws HttpException    When a violation of the HTTP protocol occurred. \r
-      */\r
-     public int putFile(String localFile, String remoteTarget, String contentType) throws HttpException, IOException {\r
-         int status = -1;\r
-         PutMethod put = new PutMethod(mUri.toString() + WebdavUtils.encodePath(remoteTarget));\r
-         \r
-         try {\r
-             File f = new File(localFile);\r
-             FileRequestEntity entity = new FileRequestEntity(f, contentType);\r
-             entity.addOnDatatransferProgressListener(mDataTransferListener);\r
-             put.setRequestEntity(entity);\r
-             status = executeMethod(put);\r
-             \r
-             exhaustResponse(put.getResponseBodyAsStream());\r
-             \r
-         } finally {\r
-             put.releaseConnection();    // let the connection available for other methods\r
-         }\r
-         return status;\r
-     }\r
-     \r
-     /**\r
-      * Tries to log in to the current URI, with the current credentials\r
-      * \r
-      * @return A {@link HttpStatus}-Code of the result. SC_OK is good.\r
-      */\r
-     public int tryToLogin() {\r
-         int status = 0;\r
-         HeadMethod head = new HeadMethod(mUri.toString());\r
-         try {\r
-             status = executeMethod(head);\r
-             boolean result = status == HttpStatus.SC_OK;\r
-             Log.d(TAG, "HEAD for " + mUri + " finished with HTTP status " + status + (!result?"(FAIL)":""));\r
-             exhaustResponse(head.getResponseBodyAsStream());\r
-             \r
-         } catch (Exception e) {\r
-             logException(e, "trying to login at " + mUri.toString());\r
-             \r
-         } finally {\r
-             head.releaseConnection();\r
-         }\r
-         return status;\r
-     }\r
\r
-     \r
-     /**\r
-      * Check if a file exists in the OC server\r
-      * \r
-      * @return              'true' if the file exists; 'false' it doesn't exist\r
-      * @throws  Exception   When the existence could not be determined\r
-      */\r
-     public boolean existsFile(String path) throws IOException, HttpException {\r
-         HeadMethod head = new HeadMethod(mUri.toString() + WebdavUtils.encodePath(path));\r
-         try {\r
-             int status = executeMethod(head);\r
-             Log.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + ((status != HttpStatus.SC_OK)?"(FAIL)":""));\r
-             exhaustResponse(head.getResponseBodyAsStream());\r
-             return (status == HttpStatus.SC_OK);\r
-             \r
-         } finally {\r
-             head.releaseConnection();    // let the connection available for other methods\r
-         }\r
-     }\r
\r
\r
-     /**\r
-      * Requests the received method with the received timeout (milliseconds).\r
-      * \r
-      * Executes the method through the inherited HttpClient.executedMethod(method).\r
-      * \r
-      * Sets the socket and connection timeouts only for the method received.\r
-      * \r
-      * The timeouts are both in milliseconds; 0 means 'infinite'; < 0 means 'do not change the default'\r
-      * \r
-      * @param method            HTTP method request.\r
-      * @param readTimeout       Timeout to set for data reception\r
-      * @param conntionTimout    Timeout to set for connection establishment\r
-      */\r
-     public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws HttpException, IOException {\r
-         int oldSoTimeout = getParams().getSoTimeout();\r
-         int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout();\r
-         try {\r
-             if (readTimeout >= 0) { \r
-                 method.getParams().setSoTimeout(readTimeout);   // this should be enough...\r
-                 getParams().setSoTimeout(readTimeout);          // ... but this looks like necessary for HTTPS\r
-             }\r
-             if (connectionTimeout >= 0) {\r
-                 getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);\r
-             }\r
-             return executeMethod(method);\r
-         } finally {\r
-             getParams().setSoTimeout(oldSoTimeout);\r
-             getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout);\r
-         }\r
-     }\r
\r
-     /**\r
-      * Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation.\r
-      * \r
-      * @param responseBodyAsStream      InputStream with the HTTP response to exhaust.\r
-      */\r
-     public void exhaustResponse(InputStream responseBodyAsStream) {\r
-         if (responseBodyAsStream != null) {\r
-             try {\r
-                 while (responseBodyAsStream.read(sExhaustBuffer) >= 0);\r
-                 responseBodyAsStream.close();\r
-             \r
-             } catch (IOException io) {\r
-                 Log.e(TAG, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED", io);\r
-             }\r
-         }\r
-     }\r
\r
\r
-     /**\r
-      * Logs an exception triggered in a HTTP request. \r
-      * \r
-      * @param e         Caught exception.\r
-      * @param doing     Suffix to add at the end of the logged message.\r
-      */\r
-     private void logException(Exception e, String doing) {\r
-         if (e instanceof HttpException) {\r
-             Log.e(TAG, "HTTP violation while " + doing, e);\r
\r
-         } else if (e instanceof IOException) {\r
-             Log.e(TAG, "Unrecovered transport exception while " + doing, e);\r
\r
-         } else {\r
-             Log.e(TAG, "Unexpected exception while " + doing, e);\r
-         }\r
-     }\r
\r
-     \r
-     /**\r
-      * Sets the connection and wait-for-data timeouts to be applied by default to the methods performed by this client.\r
-      */\r
-     public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) {\r
-             getParams().setSoTimeout(defaultDataTimeout);\r
-             getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout);\r
-     }\r
\r
-     /**\r
-      * Sets the base URI for the helper methods that receive paths as parameters, instead of full URLs\r
-      * @param uri\r
-      */\r
-     public void setBaseUri(Uri uri) {\r
-         mUri = uri;\r
-     }\r
\r
-     public Uri getBaseUri() {\r
-         return mUri;\r
-     }\r
-     \r
\r
+ /* ownCloud Android client application
+  *   Copyright (C) 2011  Bartek Przybylski
+  *   Copyright (C) 2012-2013 ownCloud Inc.
+  *
+  *   This program is free software: you can redistribute it and/or modify
+  *   it under the terms of the GNU General Public License 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 eu.alefzero.webdav;
+ import java.io.BufferedInputStream;
+ 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;
+ import org.apache.commons.httpclient.methods.PutMethod;
+ import org.apache.commons.httpclient.params.HttpMethodParams;
+ 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;
+     private Credentials mCredentials;
+     final private static String TAG = "WebdavClient";
+     private static final String USER_AGENT = "Android-ownCloud";
+     
+     private OnDatatransferProgressListener mDataTransferListener;
+     static private byte[] sExhaustBuffer = new byte[1024];
+     
+     /**
+      * Constructor
+      */
+     public WebdavClient(HttpConnectionManager connectionMgr) {
+         super(connectionMgr);
+         Log_OC.d(TAG, "Creating WebdavClient");
+         getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT);
+         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));
++    public void setBearerCredentials(String accessToken) {
++        AuthPolicy.registerAuthScheme(BearerAuthScheme.AUTH_POLICY, BearerAuthScheme.class);
++        
++        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);
+     }
 -    private Credentials getCredentials(String username, String password) {
 -        if (mCredentials == null)
 -            mCredentials = new UsernamePasswordCredentials(username, password);
 -        return mCredentials;
++    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);
+     }
+     
+     /**
+      * 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));
+         
+         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;
+     }
+     /**
 -     * 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;
 -    }
 -    
 -    
 -    /**
+      * Check if a file exists in the OC server
+      * 
+      * @return              'true' if the file exists; 'false' it doesn't exist
+      * @throws  Exception   When the existence could not be determined
+      */
+     public boolean existsFile(String path) throws IOException, HttpException {
+         HeadMethod head = new HeadMethod(mUri.toString() + WebdavUtils.encodePath(path));
+         try {
+             int status = executeMethod(head);
+             Log_OC.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + ((status != HttpStatus.SC_OK)?"(FAIL)":""));
+             exhaustResponse(head.getResponseBodyAsStream());
+             return (status == HttpStatus.SC_OK);
+             
+         } finally {
+             head.releaseConnection();    // let the connection available for other methods
+         }
+     }
 -
++    
+     /**
+      * Requests the received method with the received timeout (milliseconds).
+      * 
+      * Executes the method through the inherited HttpClient.executedMethod(method).
+      * 
+      * Sets the socket and connection timeouts only for the method received.
+      * 
+      * The timeouts are both in milliseconds; 0 means 'infinite'; < 0 means 'do not change the default'
+      * 
+      * @param method            HTTP method request.
+      * @param readTimeout       Timeout to set for data reception
+      * @param conntionTimout    Timeout to set for connection establishment
+      */
+     public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws HttpException, IOException {
+         int oldSoTimeout = getParams().getSoTimeout();
+         int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout();
+         try {
+             if (readTimeout >= 0) { 
+                 method.getParams().setSoTimeout(readTimeout);   // this should be enough...
+                 getParams().setSoTimeout(readTimeout);          // ... but this looks like necessary for HTTPS
+             }
+             if (connectionTimeout >= 0) {
+                 getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);
+             }
+             return executeMethod(method);
+         } finally {
+             getParams().setSoTimeout(oldSoTimeout);
+             getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout);
+         }
+     }
+     /**
+      * Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation.
+      * 
+      * @param responseBodyAsStream      InputStream with the HTTP response to exhaust.
+      */
+     public void exhaustResponse(InputStream responseBodyAsStream) {
+         if (responseBodyAsStream != null) {
+             try {
+                 while (responseBodyAsStream.read(sExhaustBuffer) >= 0);
+                 responseBodyAsStream.close();
+             
+             } catch (IOException io) {
+                 Log_OC.e(TAG, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED", io);
+             }
+         }
+     }
+     /**
+      * 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.
+      */
+     public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) {
+             getParams().setSoTimeout(defaultDataTimeout);
+             getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout);
+     }
+     /**
+      * Sets the base URI for the helper methods that receive paths as parameters, instead of full URLs
+      * @param uri
+      */
+     public void setBaseUri(Uri uri) {
+         mUri = uri;
+     }
+     public Uri getBaseUri() {
+         return mUri;
+     }
 +    @Override\r
 +    public int executeMethod(HostConfiguration hostconfig, final HttpMethod method, final HttpState state) throws IOException, HttpException  {\r
 +        if (mCredentials instanceof BearerCredentials) {\r
 +            method.getHostAuthState().setAuthScheme(AuthPolicy.getAuthScheme(BearerAuthScheme.AUTH_POLICY));\r
 +            method.getHostAuthState().setAuthAttempted(true);\r
 +        }\r
 +        return super.executeMethod(hostconfig, method, state);\r
 +    }\r
 +\r
 +    \r
 +    public final Credentials getCredentials() {\r
 +        return mCredentials;\r
 +    }\r
 +\r
- }\r
+ }
@@@ -24,8 -23,10 +23,9 @@@ import org.apache.jackrabbit.webdav.pro
  import org.apache.jackrabbit.webdav.property.DavPropertyName;
  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;