- extend existing FileUpload, so we can handel failed instand upload
authorMatthias Baumann <dev@mbn-cloud.de>
Mon, 25 Feb 2013 07:21:33 +0000 (08:21 +0100)
committerMatthias Baumann <dev@mbn-cloud.de>
Mon, 25 Feb 2013 07:21:33 +0000 (08:21 +0100)
later
- new Activity to handle failed instant uploads
- new Activity InstantUploadActivity can be started at two ways,
     -touch to the 'Faild Upload Notifivation'
     -submenue underneath the upload menue
- merges from head
- add lazy loading for the images list with failed uploads

12 files changed:
AndroidManifest.xml
res/layout/failed_upload_files.xml [new file with mode: 0644]
res/layout/file_activity_details.xml
res/values-de-rDE/strings.xml
res/values-de/strings.xml
res/values/strings.xml
src/com/owncloud/android/db/DbHandler.java
src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java
src/com/owncloud/android/files/services/FileUploader.java
src/com/owncloud/android/files/services/InstantUploadService.java
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/activity/InstantUploadActivity.java [new file with mode: 0644]

index 83374c3..14be678 100644 (file)
@@ -58,6 +58,8 @@
         </activity>\r
         <activity android:name=".ui.activity.UploadFilesActivity">\r
         </activity>\r
+               <activity android:name=".ui.activity.InstantUploadActivity">\r
+        </activity>\r
         <activity android:name=".Uploader" >\r
             <intent-filter>\r
                 <action android:name="android.intent.action.SEND" >\r
         <service android:name=".files.services.FileDownloader" >\r
         </service>\r
 \r
-        <activity android:name=".ui.activity.FileDetailActivity" />
+        <activity android:name=".ui.activity.FileDetailActivity" />\r
         <activity android:name=".ui.activity.PinCodeActivity" />\r
-        <activity android:name=".extensions.ExtensionsAvailableActivity"></activity>
+        <activity android:name=".extensions.ExtensionsAvailableActivity"></activity>\r
         <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=".ui.activity.ConflictsResolveActivity"/>
+        <activity android:name=".ui.activity.ConflictsResolveActivity"/>\r
         <activity android:name=".ui.activity.GenericExplanationActivity"/>\r
         <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>\r
-        
+        \r
         <service android:name=".files.services.FileUploader" >\r
-        </service>
-        <service android:name=".files.services.InstantUploadService" />
+        </service>\r
+        <service android:name=".files.services.InstantUploadService" />\r
         <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"/>
+            </intent-filter>\r
+            <intent-filter>\r
+                <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>\r
             </intent-filter>\r
         </receiver>\r
         <receiver android:name=".files.BootupBroadcastReceiver">\r
                 <action android:name="android.intent.action.BOOT_COMPLETED"/>\r
             </intent-filter>\r
         </receiver>\r
-        <service android:name=".files.services.FileObserverService"/>
+        <service android:name=".files.services.FileObserverService"/>\r
     </application>\r
 \r
-</manifest>
+</manifest>\r
diff --git a/res/layout/failed_upload_files.xml b/res/layout/failed_upload_files.xml
new file mode 100644 (file)
index 0000000..b307ff8
--- /dev/null
@@ -0,0 +1,104 @@
+<?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
+  This program is free software: you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License as published by\r
+  the Free Software Foundation, either version 3 of the License, or\r
+  (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
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="fill_parent"\r
+    android:layout_height="fill_parent"\r
+    android:background="@color/owncloud_white"\r
+    android:orientation="vertical"\r
+    android:id="@+id/failed_files_list_view">\r
+\r
+    <LinearLayout\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:layout_gravity="right"\r
+        android:orientation="horizontal" >\r
+\r
+    </LinearLayout>\r
+\r
+    <LinearLayout\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:orientation="vertical" >\r
+\r
+        <LinearLayout\r
+            android:layout_width="match_parent"\r
+            android:layout_height="wrap_content" >\r
+\r
+            <TextView\r
+                android:id="@+id/failed_upload_headline_textview"\r
+                android:layout_width="wrap_content"\r
+                android:layout_height="wrap_content"\r
+                android:layout_weight="0.93"\r
+                android:hint="@string/failed_upload_headline_hint"\r
+                android:text="@string/failed_upload_headline_text" />\r
+\r
+        </LinearLayout>\r
+\r
+        <LinearLayout\r
+            android:layout_width="match_parent"\r
+            android:layout_height="wrap_content"\r
+            android:layout_gravity="bottom|right" >\r
+\r
+            <CheckBox\r
+                android:id="@+id/failed_upload_headline_cb"\r
+                android:layout_width="wrap_content"\r
+                android:layout_height="wrap_content"\r
+                android:text="@string/failed_upload_all_cb"\r
+                android:textSize="8sp" />\r
+\r
+            <Button\r
+                android:id="@+id/failed_upload_retry_all_btn"\r
+                android:layout_width="wrap_content"\r
+                android:layout_height="wrap_content"\r
+                android:minHeight="30dp"\r
+                android:minWidth="90dp"\r
+                android:text="@string/failed_upload_headline_retryall_btn"\r
+                android:textSize="8sp" />\r
+\r
+            <Button\r
+                android:id="@+id/failed_upload_delete_all_btn"\r
+                android:layout_width="wrap_content"\r
+                android:layout_height="wrap_content"\r
+                android:minHeight="30dp"\r
+                android:minWidth="90dp"\r
+                android:text="@string/failed_upload_headline_delete_all_btn"\r
+                android:textSize="8sp" />\r
+\r
+        </LinearLayout>\r
+\r
+    </LinearLayout>\r
\r
+      <ScrollView\r
+          android:id="@+id/failedUploadScrollView"\r
+          android:layout_width="match_parent"\r
+          android:layout_height="match_parent"\r
+          android:overScrollMode="ifContentScrolls" >\r
+\r
+         <LinearLayout\r
+             android:id="@+id/failed_upload_scrollviewlayout"\r
+             android:layout_width="match_parent"\r
+             android:layout_height="wrap_content"\r
+             android:orientation="vertical">\r
+\r
+           \r
+         </LinearLayout>\r
+     </ScrollView>\r
+\r
+</LinearLayout>\r
index e325e61..e4f576c 100644 (file)
@@ -16,7 +16,8 @@
   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
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
+\r
 -->\r
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
     android:layout_width="fill_parent"\r
index 77e664d..0646f11 100644 (file)
   <string name="conflict_keep_both">Beide behalten</string>
   <string name="conflict_overwrite">Überschreiben</string>
   <string name="conflict_dont_upload">Nicht hochladen</string>
+  
+  <string name="actionbar_failed_instant_upload">Fehlgeschlagene Sofortuploads</string>  
+  <string name="failed_upload_headline_text">Fehlgeschlagene Sofortuploads</string>
+  <string name="failed_upload_headline_hint">Auflistung aller fehlgeschlagenen Softuploads</string>
+  <string name="failed_upload_all_cb">Alle auswählen</string>
+  <string name="failed_upload_headline_retryall_btn">Ausgewählte wiederholen</string>
+  <string name="failed_upload_headline_delete_all_btn">Ausgewählte löschen </string>
+  <string name="failed_upload_retry_text">Versuche ausgewählte erneut hochzuladen</string>
+  <string name="failed_upload_load_more_images">Load more Picrures</string>
+  <string name="failed_upload_retry_do_nothing_text">do nothing you are not online for instant upload</string>
 </resources>
index 3f557c9..6b72738 100644 (file)
   <string name="conflict_keep_both">Beide behalten</string>
   <string name="conflict_overwrite">Überschreiben</string>
   <string name="conflict_dont_upload">Nicht hochladen</string>
+  
+  <string name="actionbar_failed_instant_upload">Fehlgeschlagene Sofortuploads</string>  
+  <string name="failed_upload_headline_text">Fehlgeschlagene Sofortuploads</string>
+  <string name="failed_upload_headline_hint">Auflistung aller fehlgeschlagenen Softuploads</string>
+  <string name="failed_upload_all_cb">Alle auswählen</string>
+  <string name="failed_upload_headline_retryall_btn">Ausgewählte wiederholen</string>
+  <string name="failed_upload_headline_delete_all_btn">Ausgewählte löschen </string>
+  <string name="failed_upload_retry_text">Versuche ausgewählte erneut hochzuladen</string>
+  <string name="failed_upload_load_more_images">Weitere Bilder laden</string>
+<string name="failed_upload_retry_do_nothing_text">Upload nicht gestarted, Sie sind nicht online für ein Softupload</string>
 </resources>
index 8676e46..f518bda 100644 (file)
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
+
     <string name="app_name">ownCloud</string>
     <string name="whats_new">What\'s new</string>
     <string name="main_password">Password:</string>
@@ -14,9 +15,7 @@
     <string name="main_settings">Settings</string>
     <string name="main_tit_accsetup">Setup Account</string>
     <string name="main_wrn_accsetup">There is no account set up on your device. In order to use this App, you need to create one.</string>
-    
     <string name="about_message">%1$s Android App\n\nversion: %2$s</string>
-    
     <string name="actionbar_sync">Refresh</string>
     <string name="actionbar_upload">Upload</string>
     <string name="actionbar_upload_from_apps">Content from other apps</string>
@@ -24,7 +23,6 @@
     <string name="actionbar_mkdir">Create directory</string>
     <string name="actionbar_search">Search</string>
     <string name="actionbar_settings">Settings</string>
-    
     <string name="prefs_category_general">General</string>
     <string name="prefs_category_trackmydevice">Device tracking</string>
     <string name="prefs_add_session">Add new session</string>
@@ -42,7 +40,6 @@
     <string name="prefs_pincode_summary">Protect your client</string>
     <string name="prefs_instant_upload">Enable instant uploads</string>
     <string name="prefs_instant_upload_summary">Instantly upload photos taken by camera</string>
-    
     <string name="auth_host_url">URL</string>
     <string name="auth_username">Username</string>
     <string name="auth_password">Password</string>
     <string name="uploader_wrn_no_account_text">There are no %1$s accounts on your device. Please setup an account first.</string>
     <string name="uploader_wrn_no_account_setup_btn_text">Setup</string>
     <string name="uploader_wrn_no_account_quit_btn_text">Quit</string>
-       <string name="uploader_wrn_no_content_title">No content to upload</string>
-       <string name="uploader_wrn_no_content_text">No content was received. Nothing to upload.</string>
+    <string name="uploader_wrn_no_content_title">No content to upload</string>
+    <string name="uploader_wrn_no_content_text">No content was received. Nothing to upload.</string>
     <string name="uploader_error_forbidden_content">%1$s is not allowed to access the shared content</string>
     <string name="uploader_info_uploading">Uploading</string>
     <string name="uploader_btn_create_dir_text">Create directory for upload</string>
-       <string name="file_list_empty">There are no files in this folder.\nNew files can be added with the \"Upload\" menu option.</string>
+    <string name="file_list_empty">There are no files in this folder.\nNew files can be added with the \"Upload\" menu option.</string>
     <string name="filedetails_select_file">Tap on a file to display additional information.</string>
     <string name="filedetails_size">Size:</string>
     <string name="filedetails_type">Type:</string>
@@ -75,7 +72,7 @@
     <string name="filedetails_modified">Modified:</string>
     <string name="filedetails_download">Download</string>
     <string name="filedetails_sync_file">Refresh</string>
-       <string name="filedetails_redownload">Redownload</string>
+    <string name="filedetails_redownload">Redownload</string>
     <string name="filedetails_open">Open</string>
     <string name="filedetails_renamed_in_upload_msg">File was renamed to %1$s during upload</string>
     <string name="common_yes">Yes</string>
     <string name="common_ok">OK</string>
     <string name="common_cancel_download">Cancel download</string>
     <string name="common_cancel_upload">Cancel upload</string>
-       <string name="common_cancel">Cancel</string>
+    <string name="common_cancel">Cancel</string>
     <string name="common_save_exit">Save &amp; Exit</string>
     <string name="common_exit">Leave %1$s</string>
     <string name="common_error">Error</string>
     <string name="about_title">About</string>
-    
     <string name="delete_account">Delete account</string>
     <string name="create_account">Create account</string>
-    
     <string name="upload_chooser_title">Upload from &#8230;</string>
     <string name="uploader_info_dirname">Directory name</string>
-       <string name="uploader_upload_in_progress_ticker">Uploading &#8230;</string>    
-       <string name="uploader_upload_in_progress_content">%1$d%% Uploading %2$s</string>    
-       <string name="uploader_upload_succeeded_ticker">Upload succeeded</string>
+    <string name="uploader_upload_in_progress_ticker">Uploading &#8230;</string>
+    <string name="uploader_upload_in_progress_content">%1$d%% Uploading %2$s</string>
+    <string name="uploader_upload_succeeded_ticker">Upload succeeded</string>
     <string name="uploader_upload_succeeded_content_single">%1$s was successfully uploaded</string>
     <string name="uploader_upload_succeeded_content_multiple">%1$d files were successfully uploaded</string>
     <string name="uploader_upload_failed_ticker">Upload failed</string>
     <string name="downloader_download_failed_content">Download of %1$s could not be completed</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_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="foreign_files_local_text">"Local: %1$s"</string>
-       <string name="foreign_files_remote_text">"Remote: %1$s"</string>
-
-       <string name="upload_query_move_foreign_files">There is not space enough to copy the selected files into the %1$s folder. Would like to move them into instead? </string>       
-       
-       <string name="use_ssl">Use Secure Connection</string>
+    <string name="foreign_files_remote_text">"Remote: %1$s"</string>
+    <string name="upload_query_move_foreign_files">There is not space enough to copy the selected files into the %1$s folder. Would like to move them into instead? </string>
+    <string name="use_ssl">Use Secure Connection</string>
     <string name="location_no_provider">%1$s cannot track your device. Please check your location settings</string>
-    
     <string name="pincode_enter_pin_code">Please, insert your App PIN</string>
     <string name="pincode_enter_new_pin_code">Please, insert your new App PIN</string>
     <string name="pincode_configure_your_pin">Enter your App PIN</string>
-    <string name="pincode_configure_your_pin_explanation">The PIN will be requested every time the app is started</string> 
+    <string name="pincode_configure_your_pin_explanation">The PIN will be requested every time the app is started</string>
     <string name="pincode_reenter_your_pincode">Please, reenter your App PIN</string>
     <string name="pincode_remove_your_pincode">Remove your App PIN</string>
-    <string name="pincode_mismatch">The App PINs are not the same</string> 
+    <string name="pincode_mismatch">The App PINs are not the same</string>
     <string name="pincode_wrong">Incorrect App PIN</string>
     <string name="pincode_removed">App PIN removed</string>
     <string name="pincode_stored">App PIN stored</string>
-    
+
     <string-array name="prefs_trackmydevice_intervall_keys">
-       <item>15 Minutes</item>
-       <item>30 Minutes</item>
-       <item>60 Minutes</item>
-       </string-array>
-       
+        <item>15 Minutes</item>
+        <item>30 Minutes</item>
+        <item>60 Minutes</item>
+    </string-array>
     <string-array name="prefs_trackmydevice_intervall_values">
-       <item>15</item>
-       <item>30</item>
-       <item>60</item>
-       </string-array>
+        <item>15</item>
+        <item>30</item>
+        <item>60</item>
+    </string-array>
+
     <string name="auth_trying_to_login">Trying to login…</string>
     <string name="auth_no_net_conn_title">No network connection</string>
     <string name="auth_no_net_conn_message">No network connection has been detected, check your Internet connection and try again.</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_not_found">Wrong path given</string>
     <string name="auth_internal">Internal server error, code %1$d</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="extensions_avail_title">Extensions available!</string>
     <string name="extensions_avail_message">Looks like your server instance is supporting advanced extensions. Would you like to see extensions available for android ?</string>
     <string name="fd_keep_in_sync">Keep file up to date</string>
     <string name="common_share">Share</string>
     <string name="common_rename">Rename</string>
     <string name="common_remove">Remove</string>
-    
-         <string name="confirmation_remove_alert">"Do you really want to remove %1$s ?"</string>
-         <string name="confirmation_remove_folder_alert">"Do you really want to remove %1$s and its contents ?"</string>
-         <string name="confirmation_remove_local">Local only</string>
-         <string name="confirmation_remove_folder_local">Local contents only</string>
-         <string name="confirmation_remove_remote">Remove from server</string>
-         <string name="confirmation_remove_remote_and_local">Remote and local</string>
-
+    <string name="confirmation_remove_alert">"Do you really want to remove %1$s ?"</string>
+    <string name="confirmation_remove_folder_alert">"Do you really want to remove %1$s and its contents ?"</string>
+    <string name="confirmation_remove_local">Local only</string>
+    <string name="confirmation_remove_folder_local">Local contents only</string>
+    <string name="confirmation_remove_remote">Remove from server</string>
+    <string name="confirmation_remove_remote_and_local">Remote and local</string>
     <string name="remove_success_msg">"Removal succeeded"</string>
     <string name="remove_fail_msg">"Removal failed"</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="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>
     <string name="ssl_validator_label_issuer">Issued by:</string>
     <string name="ssl_validator_label_CN">Common name:</string>
     <string name="ssl_validator_label_O">Organization:</string>
-       <string name="ssl_validator_label_OU">Organizational unit:</string>
-       <string name="ssl_validator_label_C">Country:</string>
-       <string name="ssl_validator_label_ST">State:</string>
-       <string name="ssl_validator_label_L">Location:</string>
+    <string name="ssl_validator_label_OU">Organizational unit:</string>
+    <string name="ssl_validator_label_C">Country:</string>
+    <string name="ssl_validator_label_ST">State:</string>
+    <string name="ssl_validator_label_L">Location:</string>
     <string name="ssl_validator_label_validity">Validity:</string>
     <string name="ssl_validator_label_validity_from">From:</string>
-       <string name="ssl_validator_label_validity_to">To:</string>
-       <string name="ssl_validator_label_signature">Signature:</string>
-       <string name="ssl_validator_label_signature_algorithm">Algorithm:</string>
-                       
+    <string name="ssl_validator_label_validity_to">To:</string>
+    <string name="ssl_validator_label_signature">Signature:</string>
+    <string name="ssl_validator_label_signature_algorithm">Algorithm:</string>
     <string name="text_placeholder">This is a placeholder</string>
-    
     <string name="instant_upload_on_wifi">Upload pictures via WiFi only</string>
-       <string name="instant_upload_path">/InstantUpload</string>
-    
+    <string name="instant_upload_path">/InstantUpload</string>
     <string name="conflict_title">Update conflict</string>
     <string name="conflict_message">Remote file %s is not synchronized with local file. Continuing will replace content of file on server.</string>
     <string name="conflict_keep_both">Keep both</string>
     <string name="conflict_overwrite">Overwrite</string>
     <string name="conflict_dont_upload">Don\'t upload</string>
-    
+
     <!-- we need to improve the communication of errors to the user -->
     <string name="error__upload__local_file_not_copied">%1$s could not be copied to %2$s local directory</string>
-    
-</resources>
+    <string name="actionbar_failed_instant_upload">Failed InstantUpload"</string>
+    <string name="failed_upload_headline_text">Failed instant uploads</string>
+    <string name="failed_upload_headline_hint">Summary of all failed instant uploads</string>
+    <string name="failed_upload_all_cb">select all</string>
+    <string name="failed_upload_headline_retryall_btn">retry all selected</string>
+    <string name="failed_upload_headline_delete_all_btn">delete all  selected from uploadqueue</string>
+    <string name="failed_upload_retry_text">retry to upload the image: </string>
+    <string name="failed_upload_load_more_images">Load more Picrures</string>
+    <string name="failed_upload_retry_do_nothing_text">do nothing you are not online for instant upload</string>
+
+</resources>
\ No newline at end of file
index bd0fcd1..3e4103a 100644 (file)
-/* 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
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.db;
+
+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 = 2;
+
+    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) {
+        ContentValues cv = new ContentValues();
+        cv.put("path", filepath);
+        cv.put("account", account);
+        cv.put("attempt", UPLOAD_STATUS_UPLOAD_LATER);
+        long result = mDB.insert(TABLE_INSTANT_UPLOAD, null, cv);
+        Log.d(TABLE_INSTANT_UPLOAD, "putFileForLater returns with: " + result + " for file: " + filepath);
+        return result != -1;
+    }
+
+    public int updateFileState(String filepath, Integer status) {
+        ContentValues cv = new ContentValues();
+        cv.put("attempt", status);
+        int result = mDB.update(TABLE_INSTANT_UPLOAD, cv, "path=?", new String[] { filepath });
+        Log.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.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);");
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            db.execSQL("ALTER TABLE " + TABLE_INSTANT_UPLOAD + " ADD COLUMN attempt;");
+
+        }
+    }
+}
index c3ca6c8..8fd06f3 100644 (file)
@@ -21,11 +21,6 @@ package com.owncloud.android.files;
 
 import java.io.File;
 
-import com.owncloud.android.AccountUtils;
-import com.owncloud.android.authenticator.AccountAuthenticator;
-import com.owncloud.android.db.DbHandler;
-import com.owncloud.android.files.services.FileUploader;
-
 import android.accounts.Account;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -39,16 +34,18 @@ import android.provider.MediaStore.Images.Media;
 import android.util.Log;
 import android.webkit.MimeTypeMap;
 
+import com.owncloud.android.AccountUtils;
+import com.owncloud.android.authenticator.AccountAuthenticator;
+import com.owncloud.android.db.DbHandler;
+import com.owncloud.android.files.services.FileUploader;
+
 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());
@@ -68,8 +65,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
         if (intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false)) {
             DbHandler db = new DbHandler(context);
             String localPath = intent.getStringExtra(FileUploader.EXTRA_OLD_FILE_PATH);
-            if (!db.removeIUPendingFile(localPath,
-                                        intent.getStringExtra(FileUploader.ACCOUNT_NAME))) {
+            if (!db.removeIUPendingFile(localPath)) {
                 Log.w(TAG, "Tried to remove non existing instant upload file " + localPath);
             }
             db.close();
@@ -88,10 +84,8 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
             return;
         }
 
-        Cursor c = context.getContentResolver().query(intent.getData(),
-                                                      CONTENT_PROJECTION,
-                                                      null, null, null);
-        
+        Cursor c = context.getContentResolver().query(intent.getData(), CONTENT_PROJECTION, null, null, null);
+
         if (!c.moveToFirst()) {
             Log.e(TAG, "Couldn't resolve given uri: " + intent.getDataString());
             return;
@@ -102,25 +96,28 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
         String mime_type = c.getString(c.getColumnIndex(Media.MIME_TYPE));
 
         c.close();
-        Log.e(TAG, file_path+"");
-        
-        if (!isOnline(context) ||
-            (instantUploadViaWiFiOnly(context) && !isConnectedViaWiFi(context))) {
-            DbHandler db = new DbHandler(context);
-            db.putFileForLater(file_path, account.name);
-            db.close();
+        Log.e(TAG, file_path + "");
+
+        // same always temporally the picture to upload
+        DbHandler db = new DbHandler(context);
+        db.putFileForLater(file_path, account.name);
+        db.close();
+
+        if (!isOnline(context) || (instantUploadViaWiFiOnly(context) && !isConnectedViaWiFi(context))) {
             return;
         }
-        
+
         // register for upload finishe message
-        // there is a litte problem with android API, we can register for particular
-        // intent in registerReceiver but we cannot unregister from precise intent
+        // there is a litte problem with android API, we can register for
+        // particular
+        // intent in registerReceiver but we cannot unregister from precise
+        // intent
         // we can unregister from entire listenings but thats suck a bit.
         // On the other hand this might be only for dynamicly registered
         // broadcast receivers, needs investigation.
         IntentFilter filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);
         context.getApplicationContext().registerReceiver(this, filter);
-                
+
         Intent i = new Intent(context, FileUploader.class);
         i.putExtra(FileUploader.KEY_ACCOUNT, account);
         i.putExtra(FileUploader.KEY_LOCAL_FILE, file_path);
@@ -137,11 +134,10 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
             Log.d(TAG, "Instant upload disabled, abording uploading");
             return;
         }
-        
-        if (!intent.hasExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY) && 
-            isOnline(context) &&
-             (!instantUploadViaWiFiOnly(context) ||
-              (instantUploadViaWiFiOnly(context) == isConnectedViaWiFi(context) == true)) ) {
+
+        if (!intent.hasExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY)
+                && isOnline(context)
+                && (!instantUploadViaWiFiOnly(context) || (instantUploadViaWiFiOnly(context) == isConnectedViaWiFi(context) == true))) {
             DbHandler db = new DbHandler(context);
             Cursor c = db.getAwaitingFiles();
             if (c.moveToFirst()) {
@@ -156,16 +152,15 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
 
                         String mimeType = null;
                         try {
-                            mimeType = MimeTypeMap.getSingleton()
-                                    .getMimeTypeFromExtension(
-                                            f.getName().substring(f.getName().lastIndexOf('.') + 1));
-                        
+                            mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
+                                    f.getName().substring(f.getName().lastIndexOf('.') + 1));
+
                         } catch (Throwable e) {
                             Log.e(TAG, "Trying to find out MIME type of a file without extension: " + f.getName());
                         }
                         if (mimeType == null)
                             mimeType = "application/octet-stream";
-                        
+
                         Intent i = new Intent(context, FileUploader.class);
                         i.putExtra(FileUploader.KEY_ACCOUNT, account);
                         i.putExtra(FileUploader.KEY_LOCAL_FILE, file_path);
@@ -173,35 +168,35 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
                         i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
                         i.putExtra(FileUploader.KEY_INSTANT_UPLOAD, true);
                         context.startService(i);
-                        
+
                     } else {
                         Log.w(TAG, "Instant upload file " + f.getAbsolutePath() + " dont exist anymore");
                     }
-                } while(c.moveToNext());
+                } while (c.moveToNext());
             }
             c.close();
             db.close();
         }
-        
+
     }
 
-    private boolean isOnline(Context context) {
+    public static boolean isOnline(Context context) {
         ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
         return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected();
     }
-    
-    private boolean isConnectedViaWiFi(Context context) {
+
+    public static boolean isConnectedViaWiFi(Context context) {
         ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
-        return cm != null && cm.getActiveNetworkInfo() != null &&
-               cm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI &&
-               cm.getActiveNetworkInfo().getState() == State.CONNECTED;
+        return cm != null && cm.getActiveNetworkInfo() != null
+                && cm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI
+                && cm.getActiveNetworkInfo().getState() == State.CONNECTED;
     }
-    
-    private boolean instantUploadEnabled(Context context) {
+
+    public static boolean instantUploadEnabled(Context context) {
         return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_uploading", false);
     }
-    
-    private boolean instantUploadViaWiFiOnly(Context context) {
+
+    public static boolean instantUploadViaWiFiOnly(Context context) {
         return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("instant_upload_on_wifi", false);
     }
 }
index 75b8a06..eaaea01 100644 (file)
@@ -30,24 +30,6 @@ import org.apache.http.HttpStatus;
 import org.apache.jackrabbit.webdav.MultiStatus;
 import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
 
-import com.owncloud.android.authenticator.AccountAuthenticator;
-import com.owncloud.android.datamodel.FileDataStorageManager;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.files.InstantUploadBroadcastReceiver;
-import com.owncloud.android.operations.ChunkedUploadFileOperation;
-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.app.Notification;
@@ -65,9 +47,28 @@ import android.os.Process;
 import android.util.Log;
 import android.webkit.MimeTypeMap;
 import android.widget.RemoteViews;
+import android.widget.Toast;
 
 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.files.InstantUploadBroadcastReceiver;
+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.FileDetailActivity;
+import com.owncloud.android.ui.activity.InstantUploadActivity;
+import com.owncloud.android.ui.fragment.FileDetailFragment;
+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 {
 
@@ -76,20 +77,20 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";
     public static final String EXTRA_OLD_REMOTE_PATH = "OLD_REMOTE_PATH";
     public static final String EXTRA_OLD_FILE_PATH = "OLD_FILE_PATH";
-    public static final String ACCOUNT_NAME = "ACCOUNT_NAME";    
-    
+    public static final String ACCOUNT_NAME = "ACCOUNT_NAME";
+
     public static final String KEY_FILE = "FILE";
     public static final String KEY_LOCAL_FILE = "LOCAL_FILE";
     public static final String KEY_REMOTE_FILE = "REMOTE_FILE";
     public static final String KEY_MIME_TYPE = "MIME_TYPE";
 
     public static final String KEY_ACCOUNT = "ACCOUNT";
-    
+
     public static final String KEY_UPLOAD_TYPE = "UPLOAD_TYPE";
     public static final String KEY_FORCE_OVERWRITE = "KEY_FORCE_OVERWRITE";
     public static final String KEY_INSTANT_UPLOAD = "INSTANT_UPLOAD";
     public static final String KEY_LOCAL_BEHAVIOUR = "BEHAVIOUR";
-    
+
     public static final int LOCAL_BEHAVIOUR_COPY = 0;
     public static final int LOCAL_BEHAVIOUR_MOVE = 1;
     public static final int LOCAL_BEHAVIOUR_FORGET = 2;
@@ -98,7 +99,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     public static final int UPLOAD_MULTIPLE_FILES = 1;
 
     private static final String TAG = FileUploader.class.getSimpleName();
-    
+
     private Looper mServiceLooper;
     private ServiceHandler mServiceHandler;
     private IBinder mBinder;
@@ -108,18 +109,17 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
 
     private ConcurrentMap<String, UploadFileOperation> mPendingUploads = new ConcurrentHashMap<String, UploadFileOperation>();
     private UploadFileOperation mCurrentUpload = null;
-    
+
     private NotificationManager mNotificationManager;
     private Notification mNotification;
     private int mLastPercent;
     private RemoteViews mDefaultNotificationContentView;
-    
-    
+
     /**
      * Builds a key for mPendingUploads from the account and file to upload
      * 
-     * @param account   Account where the file to download is stored
-     * @param file      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();
@@ -129,44 +129,44 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         return account.name + remotePath;
     }
 
-    
     /**
      * Checks if an ownCloud server version should support chunked uploads.
      * 
-     * @param version   OwnCloud version instance corresponding to an ownCloud server.
-     * @return          'True' if the ownCloud server with version supports chunked uploads.
+     * @param version OwnCloud version instance corresponding to an ownCloud
+     *            server.
+     * @return 'True' if the ownCloud server with version supports chunked
+     *         uploads.
      */
     private static boolean chunkedUploadIsSupported(OwnCloudVersion version) {
         return (version != null && version.compareTo(OwnCloudVersion.owncloud_v4_5) >= 0);
     }
 
-    
-
     /**
      * Service initialization
      */
     @Override
     public void onCreate() {
         super.onCreate();
+        Log.i(TAG, "mPendingUploads size:" + mPendingUploads.size());
         mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
-        HandlerThread thread = new HandlerThread("FileUploaderThread",
-                Process.THREAD_PRIORITY_BACKGROUND);
+        HandlerThread thread = new HandlerThread("FileUploaderThread", Process.THREAD_PRIORITY_BACKGROUND);
         thread.start();
         mServiceLooper = thread.getLooper();
         mServiceHandler = new ServiceHandler(mServiceLooper, this);
         mBinder = new FileUploaderBinder();
     }
 
-    
     /**
      * Entry point to add one or several files to the queue of uploads.
      * 
-     * New uploads 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.
+     * New uploads 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(KEY_ACCOUNT) || !intent.hasExtra(KEY_UPLOAD_TYPE) || !(intent.hasExtra(KEY_LOCAL_FILE) || intent.hasExtra(KEY_FILE))) {
+        if (!intent.hasExtra(KEY_ACCOUNT) || !intent.hasExtra(KEY_UPLOAD_TYPE)
+                || !(intent.hasExtra(KEY_LOCAL_FILE) || intent.hasExtra(KEY_FILE))) {
             Log.e(TAG, "Not enough information provided in intent");
             return Service.START_NOT_STICKY;
         }
@@ -176,25 +176,30 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
             return Service.START_NOT_STICKY;
         }
         Account account = intent.getParcelableExtra(KEY_ACCOUNT);
-        
+
         String[] localPaths = null, remotePaths = null, mimeTypes = null;
         OCFile[] files = null;
         if (uploadType == UPLOAD_SINGLE_FILE) {
-            
+
             if (intent.hasExtra(KEY_FILE)) {
-                files = new OCFile[] {intent.getParcelableExtra(KEY_FILE) };
-                
+                files = new OCFile[] { intent.getParcelableExtra(KEY_FILE) };
+
             } else {
                 localPaths = new String[] { intent.getStringExtra(KEY_LOCAL_FILE) };
                 remotePaths = new String[] { intent.getStringExtra(KEY_REMOTE_FILE) };
                 mimeTypes = new String[] { intent.getStringExtra(KEY_MIME_TYPE) };
             }
-            
+
         } else { // mUploadType == UPLOAD_MULTIPLE_FILES
-            
+
             if (intent.hasExtra(KEY_FILE)) {
-                files = (OCFile[]) intent.getParcelableArrayExtra(KEY_FILE);    // TODO will this casting work fine?
-                
+                files = (OCFile[]) intent.getParcelableArrayExtra(KEY_FILE); // TODO
+                                                                             // will
+                                                                             // this
+                                                                             // casting
+                                                                             // work
+                                                                             // fine?
+
             } else {
                 localPaths = intent.getStringArrayExtra(KEY_LOCAL_FILE);
                 remotePaths = intent.getStringArrayExtra(KEY_REMOTE_FILE);
@@ -203,19 +208,24 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         }
 
         FileDataStorageManager storageManager = new FileDataStorageManager(account, getContentResolver());
-        
+
         boolean forceOverwrite = intent.getBooleanExtra(KEY_FORCE_OVERWRITE, false);
         boolean isInstant = intent.getBooleanExtra(KEY_INSTANT_UPLOAD, false);
         int localAction = intent.getIntExtra(KEY_LOCAL_BEHAVIOUR, LOCAL_BEHAVIOUR_COPY);
         boolean fixed = false;
         if (isInstant) {
-            fixed = checkAndFixInstantUploadDirectory(storageManager);  // MUST be done BEFORE calling obtainNewOCFileToUpload
+            fixed = checkAndFixInstantUploadDirectory(storageManager); // MUST
+                                                                       // be
+                                                                       // done
+                                                                       // BEFORE
+                                                                       // calling
+                                                                       // obtainNewOCFileToUpload
         }
-        
+
         if (intent.hasExtra(KEY_FILE) && files == null) {
             Log.e(TAG, "Incorrect array for OCFiles provided in upload intent");
             return Service.START_NOT_STICKY;
-            
+
         } else if (!intent.hasExtra(KEY_FILE)) {
             if (localPaths == null) {
                 Log.e(TAG, "Incorrect array for local paths provided in upload intent");
@@ -229,63 +239,71 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                 Log.e(TAG, "Different number of remote paths and local paths!");
                 return Service.START_NOT_STICKY;
             }
-            
+
             files = new OCFile[localPaths.length];
-            for (int i=0; i < localPaths.length; i++) {
-                files[i] = obtainNewOCFileToUpload(remotePaths[i], localPaths[i], ((mimeTypes!=null)?mimeTypes[i]:(String)null), storageManager);
+            for (int i = 0; i < localPaths.length; i++) {
+                files[i] = obtainNewOCFileToUpload(remotePaths[i], localPaths[i], ((mimeTypes != null) ? mimeTypes[i]
+                        : (String) null), storageManager);
+                if (files[i] == null) {
+                    // TODO @andromaex add failure Notiification
+                    return Service.START_NOT_STICKY;
+                }
             }
         }
-            
-        OwnCloudVersion ocv = new OwnCloudVersion(AccountManager.get(this).getUserData(account, AccountAuthenticator.KEY_OC_VERSION));
+
+        OwnCloudVersion ocv = new OwnCloudVersion(AccountManager.get(this).getUserData(account,
+                AccountAuthenticator.KEY_OC_VERSION));
         boolean chunked = FileUploader.chunkedUploadIsSupported(ocv);
         AbstractList<String> requestedUploads = new Vector<String>();
         String uploadKey = null;
         UploadFileOperation newUpload = null;
         try {
-            for (int i=0; i < files.length; i++) {
+            for (int i = 0; i < files.length; i++) {
                 uploadKey = buildRemoteName(account, files[i].getRemotePath());
                 if (chunked) {
-                    newUpload = new ChunkedUploadFileOperation(account, files[i], isInstant, forceOverwrite, localAction);
+                    newUpload = new ChunkedUploadFileOperation(account, files[i], isInstant, forceOverwrite,
+                            localAction);
                 } else {
                     newUpload = new UploadFileOperation(account, files[i], isInstant, forceOverwrite, localAction);
                 }
-                if (fixed && i==0) {
+                if (fixed && i == 0) {
                     newUpload.setRemoteFolderToBeCreated();
                 }
                 mPendingUploads.putIfAbsent(uploadKey, newUpload);
                 newUpload.addDatatransferProgressListener(this);
                 requestedUploads.add(uploadKey);
             }
-            
+
         } catch (IllegalArgumentException e) {
             Log.e(TAG, "Not enough information provided in intent: " + e.getMessage());
             return START_NOT_STICKY;
-            
+
         } catch (IllegalStateException e) {
             Log.e(TAG, "Bad information provided in intent: " + e.getMessage());
             return START_NOT_STICKY;
-            
+
         } catch (Exception e) {
             Log.e(TAG, "Unexpected exception while processing upload intent", e);
             return START_NOT_STICKY;
-            
+
         }
-        
+
         if (requestedUploads.size() > 0) {
             Message msg = mServiceHandler.obtainMessage();
             msg.arg1 = startId;
             msg.obj = requestedUploads;
             mServiceHandler.sendMessage(msg);
         }
-
+        Log.i(TAG, "mPendingUploads size:" + mPendingUploads.size());
         return Service.START_NOT_STICKY;
     }
 
-    
     /**
-     * Provides a binder object that clients can use to perform operations on the queue of uploads, excepting the addition of new files. 
+     * Provides a binder object that clients can use to perform operations on
+     * the queue of uploads, excepting the addition of new files.
      * 
-     * Implemented to perform cancellation, pause and resume of existing uploads.
+     * Implemented to perform cancellation, pause and resume of existing
+     * uploads.
      */
     @Override
     public IBinder onBind(Intent arg0) {
@@ -293,17 +311,18 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     }
 
     /**
-     *  Binder to let client components to perform operations on the queue of uploads.
+     * Binder to let client components to perform operations on the queue of
+     * uploads.
      * 
-     *  It provides by itself the available operations.
+     * It provides by itself the available operations.
      */
     public class FileUploaderBinder extends Binder {
-        
+
         /**
          * Cancels a pending or current upload of a remote file.
          * 
-         * @param account       Owncloud account where the remote file will be stored.
-         * @param file          A file in the queue of pending uploads
+         * @param account Owncloud account where the remote file will be stored.
+         * @param file A file in the queue of pending uploads
          */
         public void cancel(Account account, OCFile file) {
             UploadFileOperation upload = null;
@@ -314,18 +333,20 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                 upload.cancel();
             }
         }
-        
-        
+
         /**
-         * Returns True when the file described by 'file' is being uploaded to the ownCloud account 'account' or waiting for it
+         * Returns True when the file described by 'file' is being uploaded to
+         * the ownCloud account 'account' or waiting for it
          * 
-         * If 'file' is a directory, returns 'true' if some of its descendant files 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 will be stored.
-         * @param file          A file that could be in the queue of pending uploads
+         * @param account Owncloud account where the remote file will be stored.
+         * @param file A file that could be in the queue of pending uploads
          */
         public boolean isUploading(Account account, OCFile file) {
-            if (account == null || file == null) return false;
+            if (account == null || file == null)
+                return false;
             String targetKey = buildRemoteName(account, file);
             synchronized (mPendingUploads) {
                 if (file.isDirectory()) {
@@ -342,18 +363,19 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
             }
         }
     }
-    
-    
-    
-    
-    /** 
-     * Upload worker. Performs the pending uploads in the order they were requested. 
+
+    /**
+     * Upload worker. Performs the pending uploads in the order they were
+     * requested.
      * 
-     * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}. 
+     * 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
+        // don't make it a final class, and don't remove the static ; lint will
+        // warn about a possible memory leak
         FileUploader mService;
+
         public ServiceHandler(Looper looper, FileUploader service) {
             super(looper);
             if (service == null)
@@ -375,66 +397,84 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         }
     }
 
-    
-    
-    
     /**
      * Core upload method: sends the file(s) to upload
      * 
-     * @param uploadKey   Key to access the upload to perform, contained in mPendingUploads
+     * @param uploadKey Key to access the upload to perform, contained in
+     *            mPendingUploads
      */
     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
+            // / 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
+
+            // / create remote folder for instant uploads
             if (mCurrentUpload.isRemoteFolderToBeCreated()) {
-                mUploadClient.createDirectory(InstantUploadBroadcastReceiver.INSTANT_UPLOAD_DIR);    // ignoring result; fail could just mean that it already exists, but local database is not synchronized; the upload will be tried anyway
+                mUploadClient.createDirectory(InstantUploadBroadcastReceiver.INSTANT_UPLOAD_DIR); // ignoring
+                                                                                                  // result;
+                                                                                                  // fail
+                                                                                                  // could
+                                                                                                  // just
+                                                                                                  // mean
+                                                                                                  // that
+                                                                                                  // it
+                                                                                                  // already
+                                                                                                  // exists,
+                                                                                                  // but
+                                                                                                  // local
+                                                                                                  // database
+                                                                                                  // is
+                                                                                                  // not
+                                                                                                  // synchronized;
+                                                                                                  // the
+                                                                                                  // upload
+                                                                                                  // will
+                                                                                                  // be
+                                                                                                  // tried
+                                                                                                  // anyway
             }
 
-            
-            /// perform the upload
+            // / perform the upload
             RemoteOperationResult uploadResult = null;
             try {
                 uploadResult = mCurrentUpload.execute(mUploadClient);
                 if (uploadResult.isSuccess()) {
                     saveUploadedFile();
                 }
-                
+
             } finally {
-                synchronized(mPendingUploads) {
+                synchronized (mPendingUploads) {
                     mPendingUploads.remove(uploadKey);
+                    Log.i(TAG, "Remove CurrentUploadItem from pending upload Item Map.");
                 }
             }
-        
-            /// notify result
+
+            // notify result
             notifyUploadResult(uploadResult, mCurrentUpload);
-            
             sendFinalBroadcast(mCurrentUpload, uploadResult);
-            
+
         }
-        
+
     }
 
     /**
      * Saves a OC File after a successful upload.
      * 
-     * A PROPFIND is necessary to keep the props in the local database synchronized with the server, 
-     * specially the modification time and Etag (where available)
+     * A PROPFIND is necessary to keep the props in the local database
+     * synchronized with the server, specially the modification time and Etag
+     * (where available)
      * 
      * TODO refactor this ugly thing
      */
@@ -442,94 +482,107 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         OCFile file = mCurrentUpload.getFile();
         long syncDate = System.currentTimeMillis();
         file.setLastSyncDateForData(syncDate);
-        
-        /// new PROPFIND to keep data consistent with server in theory, should return the same we already have
+
+        // / new PROPFIND to keep data consistent with server in theory, should
+        // return the same we already have
         PropFindMethod propfind = null;
         RemoteOperationResult result = null;
         try {
-          propfind = new PropFindMethod(mUploadClient.getBaseUri() + WebdavUtils.encodePath(mCurrentUpload.getRemotePath()));
-          int status = mUploadClient.executeMethod(propfind);
-          boolean isMultiStatus = (status == HttpStatus.SC_MULTI_STATUS);
-          if (isMultiStatus) {
-              MultiStatus resp = propfind.getResponseBodyAsMultiStatus();
-              WebdavEntry we = new WebdavEntry(resp.getResponses()[0],
-                                               mUploadClient.getBaseUri().getPath());
-              updateOCFile(file, we);
-              file.setLastSyncDateForProperties(syncDate);
-              
-          } else {
-              mUploadClient.exhaustResponse(propfind.getResponseBodyAsStream());
-          }
-          
-          result = new RemoteOperationResult(isMultiStatus, status);
-          Log.i(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": " + result.getLogMessage());
-          
+            propfind = new PropFindMethod(mUploadClient.getBaseUri()
+                    + WebdavUtils.encodePath(mCurrentUpload.getRemotePath()));
+            int status = mUploadClient.executeMethod(propfind);
+            boolean isMultiStatus = (status == HttpStatus.SC_MULTI_STATUS);
+            if (isMultiStatus) {
+                MultiStatus resp = propfind.getResponseBodyAsMultiStatus();
+                WebdavEntry we = new WebdavEntry(resp.getResponses()[0], mUploadClient.getBaseUri().getPath());
+                updateOCFile(file, we);
+                file.setLastSyncDateForProperties(syncDate);
+
+            } else {
+                mUploadClient.exhaustResponse(propfind.getResponseBodyAsStream());
+            }
+
+            result = new RemoteOperationResult(isMultiStatus, status);
+            Log.i(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": "
+                    + result.getLogMessage());
+
         } catch (Exception e) {
             result = new RemoteOperationResult(e);
-            Log.e(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": " + result.getLogMessage(), e);
+            Log.e(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": "
+                    + result.getLogMessage(), e);
 
         } finally {
             if (propfind != null)
                 propfind.releaseConnection();
         }
 
-        /// maybe this would be better as part of UploadFileOperation... or maybe all this method
+        // / maybe this would be better as part of UploadFileOperation... or
+        // maybe all this method
         if (mCurrentUpload.wasRenamed()) {
             OCFile oldFile = mCurrentUpload.getOldFile();
             if (oldFile.fileExists()) {
                 oldFile.setStoragePath(null);
                 mStorageManager.saveFile(oldFile);
-                
-            } // else: it was just an automatic renaming due to a name coincidence; nothing else is needed, the storagePath is right in the instance returned by mCurrentUpload.getFile()
+
+            } // else: it was just an automatic renaming due to a name
+              // coincidence; nothing else is needed, the storagePath is right
+              // in the instance returned by mCurrentUpload.getFile()
         }
-        
+
         mStorageManager.saveFile(file);
     }
 
-    
     private void updateOCFile(OCFile file, WebdavEntry we) {
         file.setCreationTimestamp(we.createTimestamp());
         file.setFileLength(we.contentLength());
         file.setMimetype(we.contentType());
         file.setModificationTimestamp(we.modifiedTimestamp());
         file.setModificationTimestampAtLastSyncForData(we.modifiedTimestamp());
-        // file.setEtag(mCurrentDownload.getEtag());    // TODO Etag, where available
+        // file.setEtag(mCurrentDownload.getEtag()); // TODO Etag, where
+        // available
     }
-    
-    
+
     private boolean checkAndFixInstantUploadDirectory(FileDataStorageManager storageManager) {
         OCFile instantUploadDir = storageManager.getFileByPath(InstantUploadBroadcastReceiver.INSTANT_UPLOAD_DIR);
         if (instantUploadDir == null) {
-            // first instant upload in the account, or never account not synchronized after the remote InstantUpload folder was created
+            // first instant upload in the account, or never account not
+            // synchronized after the remote InstantUpload folder was created
             OCFile newDir = new OCFile(InstantUploadBroadcastReceiver.INSTANT_UPLOAD_DIR);
             newDir.setMimetype("DIR");
-            newDir.setParentId(storageManager.getFileByPath(OCFile.PATH_SEPARATOR).getFileId());
-            storageManager.saveFile(newDir);
-            return true;
+            OCFile path = storageManager.getFileByPath(OCFile.PATH_SEPARATOR);
+
+            if (path != null) {
+                newDir.setParentId(path.getFileId());
+                storageManager.saveFile(newDir);
+                return true;
+            } else {
+                return false;
+            }
+
         }
         return false;
     }
 
-    
-    private OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType, FileDataStorageManager storageManager) {
+    private OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType,
+            FileDataStorageManager storageManager) {
         OCFile newFile = new OCFile(remotePath);
         newFile.setStoragePath(localPath);
         newFile.setLastSyncDateForProperties(0);
         newFile.setLastSyncDateForData(0);
-        
+
         // size
         if (localPath != null && localPath.length() > 0) {
             File localFile = new File(localPath);
             newFile.setFileLength(localFile.length());
             newFile.setLastSyncDateForData(localFile.lastModified());
-        }   // don't worry about not assigning size, the problems with localPath are checked when the UploadFileOperation instance is created
-        
+        } // don't worry about not assigning size, the problems with localPath
+          // are checked when the UploadFileOperation instance is created
+
         // MIME type
         if (mimeType == null || mimeType.length() <= 0) {
             try {
-                mimeType = MimeTypeMap.getSingleton()
-                    .getMimeTypeFromExtension(
-                            remotePath.substring(remotePath.lastIndexOf('.') + 1));
+                mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
+                        remotePath.substring(remotePath.lastIndexOf('.') + 1));
             } catch (IndexOutOfBoundsException e) {
                 Log.e(TAG, "Trying to find out MIME type of a file without extension: " + remotePath);
             }
@@ -538,53 +591,62 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
             mimeType = "application/octet-stream";
         }
         newFile.setMimetype(mimeType);
-        
+
         // parent dir
         String parentPath = new File(remotePath).getParent();
-        parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR ;
+        parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR;
         OCFile parentDir = storageManager.getFileByPath(parentPath);
         if (parentDir == null) {
-            throw new IllegalStateException("Can not upload a file to a non existing remote location: " + parentPath);
+            Toast t = Toast
+                    .makeText(
+                            getApplicationContext(),
+                            "The first time the InstantUpload is running you must be online, so the target folder can successfully created by the upload process",
+                            30);
+            t.show();
+            return null;
         }
         long parentDirId = parentDir.getFileId();
         newFile.setParentId(parentDirId);
         return newFile;
     }
-    
 
     /**
      * Creates a status notification to show the upload progress
      * 
-     * @param upload    Upload operation starting.
+     * @param upload Upload operation starting.
      */
     private void notifyUploadStart(UploadFileOperation upload) {
-        /// create status notification with a progress bar
+        // / create status notification with a progress bar
         mLastPercent = 0;
-        mNotification = new Notification(R.drawable.icon, getString(R.string.uploader_upload_in_progress_ticker), System.currentTimeMillis());
+        mNotification = new Notification(R.drawable.icon, getString(R.string.uploader_upload_in_progress_ticker),
+                System.currentTimeMillis());
         mNotification.flags |= Notification.FLAG_ONGOING_EVENT;
         mDefaultNotificationContentView = mNotification.contentView;
-        mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbar_layout);
+        mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(),
+                R.layout.progressbar_layout);
         mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, false);
-        mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.uploader_upload_in_progress_content), 0, upload.getFileName()));
+        mNotification.contentView.setTextViewText(R.id.status_text,
+                String.format(getString(R.string.uploader_upload_in_progress_content), 0, upload.getFileName()));
         mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon);
-        
-        /// includes a pending intent in the notification showing the details view of the file
+
+        // / includes a pending intent in the notification showing the details
+        // view of the file
         Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
         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.contentIntent = PendingIntent.getActivity(getApplicationContext(),
+                (int) System.currentTimeMillis(), showDetailsIntent, 0);
+
         mNotificationManager.notify(R.string.uploader_upload_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));
+        int percent = (int) (100.0 * ((double) totalTransferredSoFar) / ((double) totalToTransfer));
         if (percent != mLastPercent) {
             mNotification.contentView.setProgressBar(R.id.status_progress, 100, percent, false);
             String text = String.format(getString(R.string.uploader_upload_in_progress_content), percent, fileName);
@@ -593,98 +655,112 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         }
         mLastPercent = percent;
     }
-    
-    
+
     /**
-     * Callback method to update the progress bar in the status notification  (old version)
+     * 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 an upload operation.
      * 
-     * @param uploadResult    Result of the upload operation.
-     * @param upload          Finished upload operation
+     * @param uploadResult Result of the upload operation.
+     * @param upload Finished upload operation
      */
     private void notifyUploadResult(RemoteOperationResult uploadResult, UploadFileOperation upload) {
+        Log.d(TAG, "NotifyUploadResult with resultCode: " + uploadResult.getCode());
         if (uploadResult.isCancelled()) {
-            /// cancelled operation -> silent removal of progress notification
+            // / cancelled operation -> silent removal of progress notification
             mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker);
-            
+
         } else if (uploadResult.isSuccess()) {
-            /// success -> silent update of progress notification to success message 
-            mNotification.flags ^= Notification.FLAG_ONGOING_EVENT; // remove the ongoing flag
+            // / success -> silent update of progress notification to success
+            // message
+            mNotification.flags ^= Notification.FLAG_ONGOING_EVENT; // remove
+                                                                    // the
+                                                                    // ongoing
+                                                                    // flag
             mNotification.flags |= Notification.FLAG_AUTO_CANCEL;
             mNotification.contentView = mDefaultNotificationContentView;
-            
-            /// includes a pending intent in the notification showing the details view of the file
+
+            // / includes a pending intent in the notification showing the
+            // details view of the file
             Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
             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;
-            // 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));
+
+            Intent detailUploudIntent = new Intent(this, InstantUploadActivity.class);
+            detailUploudIntent.putExtra(FileUploader.KEY_ACCOUNT, upload.getAccount());
+            finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(),
+                    (int) System.currentTimeMillis(), detailUploudIntent, PendingIntent.FLAG_UPDATE_CURRENT
+                            | PendingIntent.FLAG_ONE_SHOT);
+
+            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 {
-                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);
-            
+            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);
-            } */                
+
+            DbHandler db = new DbHandler(this.getBaseContext());
+            if (db.updateFileState(upload.getOriginalStoragePath(), DbHandler.UPLOAD_STATUS_UPLOAD_FAILED) == 0) {
+                db.putFileForLater(upload.getOriginalStoragePath(), upload.getAccount().name);
+            }
+            db.close();
+
         }
-        
+
     }
-    
-    
+
     /**
-     * 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);
-        end.putExtra(EXTRA_REMOTE_PATH, upload.getRemotePath());    // real remote path, after possible automatic renaming
+        end.putExtra(EXTRA_REMOTE_PATH, upload.getRemotePath()); // real remote
+                                                                 // path, after
+                                                                 // possible
+                                                                 // automatic
+                                                                 // renaming
         if (upload.wasRenamed()) {
             end.putExtra(EXTRA_OLD_REMOTE_PATH, upload.getOldFile().getRemotePath());
         }
@@ -694,5 +770,4 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         sendStickyBroadcast(end);
     }
 
-
 }
index d7cf498..ae1cb05 100644 (file)
@@ -40,22 +40,22 @@ public class InstantUploadService extends Service {
     public static String KEY_MIME_TYPE = "KEY_MIMETYPE";
     public static String KEY_DISPLAY_NAME = "KEY_FILENAME";
     public static String KEY_ACCOUNT = "KEY_ACCOUNT";
-    
+
     private static String TAG = "InstantUploadService";
-    private static String INSTANT_UPLOAD_DIR = "/InstantUpload";
+    // TODO make it configurable over the settings dialog
+    public static String INSTANT_UPLOAD_DIR = "/InstantUpload";
     private UploaderRunnable mUploaderRunnable;
-    
+
     @Override
     public IBinder onBind(Intent arg0) {
         return null;
     }
-    
+
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
-        if (intent == null ||
-            !intent.hasExtra(KEY_ACCOUNT) || !intent.hasExtra(KEY_DISPLAY_NAME) ||
-            !intent.hasExtra(KEY_FILE_PATH) || !intent.hasExtra(KEY_FILE_SIZE) ||
-            !intent.hasExtra(KEY_MIME_TYPE)) {
+        if (intent == null || !intent.hasExtra(KEY_ACCOUNT) || !intent.hasExtra(KEY_DISPLAY_NAME)
+                || !intent.hasExtra(KEY_FILE_PATH) || !intent.hasExtra(KEY_FILE_SIZE)
+                || !intent.hasExtra(KEY_MIME_TYPE)) {
             Log.w(TAG, "Not all required information was provided, abording");
             return Service.START_NOT_STICKY;
         }
index 05b5d33..46ed65e 100644 (file)
-/* 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.authenticator.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.network.OwnCloudClientUtils;\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
-import eu.alefzero.webdav.WebdavClient;\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
-    \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
-        /// Load of parameters from received intent\r
-        mCurrentDir = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); // no check necessary, mCurrenDir == null if the parameter is not in the intent\r
-        Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);\r
-        if (account != null)\r
-            AccountUtils.setCurrentOwnCloudAccount(this, account.name);\r
-        \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(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.AUTH_TOKEN_TYPE });\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.AUTH_TOKEN_TYPE);   // cancel the current synchronizations of any ownCloud account\r
-        Bundle bundle = new Bundle();\r
-        bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);\r
-        ContentResolver.requestSync(\r
-                AccountUtils.getCurrentOwnCloudAccount(this),\r
-                AccountAuthenticator.AUTH_TOKEN_TYPE, bundle);\r
-    }\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
-                            Thread thread = new Thread(new DirectoryCreator(path,  AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), new Handler()));\r
-                            thread.start();\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
-    private class DirectoryCreator implements Runnable {\r
-        private String mTargetPath;\r
-        private Account mAccount;\r
-        private Handler mHandler; \r
-    \r
-        public DirectoryCreator(String targetPath, Account account, Handler handler) {\r
-            mTargetPath = targetPath;\r
-            mAccount = account;\r
-            mHandler = handler;\r
-        }\r
-    \r
-        @Override\r
-        public void run() {\r
-            WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext());\r
-            boolean created = wdc.createDirectory(mTargetPath);\r
-            if (created) {\r
-                mHandler.post(new Runnable() {\r
-                    @Override\r
-                    public void run() { \r
-                        dismissDialog(DIALOG_SHORT_WAIT);\r
-                        \r
-                        // Save new directory in local database\r
-                        OCFile newDir = new OCFile(mTargetPath);\r
-                        newDir.setMimetype("DIR");\r
-                        newDir.setParentId(mCurrentDir.getFileId());\r
-                        mStorageManager.saveFile(newDir);\r
-    \r
-                        // Display the new folder right away\r
-                        mFileList.listDirectory();\r
-                    }\r
-                });\r
-                \r
-            } else {\r
-                mHandler.post(new Runnable() {\r
-                    @Override\r
-                    public void run() {\r
-                        dismissDialog(DIALOG_SHORT_WAIT);\r
-                        try {\r
-                            Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); \r
-                            msg.show();\r
-                        \r
-                        } catch (NotFoundException e) {\r
-                            Log.e(TAG, "Error while trying to show fail message " , e);\r
-                        }\r
-                    }\r
-                });\r
-            }\r
-        }\r
-    \r
-    }\r
-\r
-    // Custom array adapter to override text colors\r
-    private class CustomArrayAdapter<T> extends ArrayAdapter<T> {\r
-    \r
-        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
-    }\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 as published by
+ *   the Free Software Foundation, either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.ui.activity;
+
+import java.io.File;
+
+import android.accounts.Account;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+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.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources.NotFoundException;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+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.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.R;
+import com.owncloud.android.authenticator.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.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.syncadapter.FileSyncService;
+import com.owncloud.android.ui.dialog.ChangelogDialog;
+import com.owncloud.android.ui.dialog.SslValidatorDialog;
+import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;
+import com.owncloud.android.ui.fragment.FileDetailFragment;
+import com.owncloud.android.ui.fragment.OCFileListFragment;
+
+import eu.alefzero.webdav.WebdavClient;
+
+/**
+ * Displays, what files the user has available in his ownCloud.
+ * 
+ * @author Bartek Przybylski
+ * 
+ */
+
+public class FileDisplayActivity extends SherlockFragmentActivity implements OCFileListFragment.ContainerActivity,
+        FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, OnRemoteOperationListener {
+
+    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 static final int DIALOG_SETUP_ACCOUNT = 0;
+    private static final int DIALOG_CREATE_DIR = 1;
+    private static final int DIALOG_ABOUT_APP = 2;
+    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";
+
+    
+    private static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;
+    private static final int ACTION_SELECT_MULTIPLE_FILES = 2;
+    private static final int ACTION_SELECT_FAILED_INSTANT_UPLOAD = 2;
+
+    private static final String TAG = "FileDisplayActivity";
+
+    private static int[] mMenuIdentifiersToPatch = {R.id.about_app};
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        Log.d(getClass().toString(), "onCreate() start");
+        super.onCreate(savedInstanceState);
+
+        /// Load of parameters from received intent
+        mCurrentDir = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); // no check necessary, mCurrenDir == null if the parameter is not in the intent
+        Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);
+        if (account != null)
+            AccountUtils.setCurrentOwnCloudAccount(this, account.name);
+        
+        /// 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, or SOME TIMES
+            mCurrentDir = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE);
+        }
+        
+        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 (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) {
+            initFileDetailsInDualPane();
+        }
+            
+        // 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();
+        
+        Log.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 });
+        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) {
+                transaction.replace(R.id.file_details_container,
+                        new FileDetailFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)),
+                        FileDetailFragment.FTAG); // empty FileDetailFragment
+                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.menu, menu);
+            
+            patchHiddenAccents(menu);
+            
+            return true;
+    }
+
+    /**
+     * 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> 
+     * 
+     * @param menu      Menu to patch
+     */
+    private void patchHiddenAccents(Menu menu) {
+        for (int i = 0; i < mMenuIdentifiersToPatch.length ; i++) {
+            MenuItem aboutItem = menu.findItem(mMenuIdentifiersToPatch[i]);
+            if (aboutItem != null && aboutItem.getIcon() instanceof BitmapDrawable) {
+                // Clip off the bottom three (density independent) pixels of transparent padding
+                Bitmap original = ((BitmapDrawable) aboutItem.getIcon()).getBitmap();
+                float scale = getResources().getDisplayMetrics().density;
+                int clippedHeight = (int) (original.getHeight() - (3 * scale));
+                Bitmap scaled = Bitmap.createBitmap(original, 0, 0, original.getWidth(), clippedHeight);
+                aboutItem.setIcon(new BitmapDrawable(getResources(), scaled));
+            }
+        }
+    }
+
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        boolean retval = true;
+        switch (item.getItemId()) {
+        case R.id.createDirectoryItem: {
+            showDialog(DIALOG_CREATE_DIR);
+            break;
+        }
+        case R.id.startSync: {
+            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 R.id.about_app: {
+            showDialog(DIALOG_ABOUT_APP);
+            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
+        Bundle bundle = new Bundle();
+        bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+        ContentResolver.requestSync(
+                AccountUtils.getCurrentOwnCloudAccount(this),
+                AccountAuthenticator.AUTH_TOKEN_TYPE, 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.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.e("FileDisplay", "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e);
+            e.printStackTrace();
+            
+        } finally {
+            if (filepath == null) {
+                Log.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
+            FileDetailFragment fileDetails = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(
+                    FileDetailFragment.FTAG);
+            if (fileDetails != null && !fileDetails.isEmpty()) {
+                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+                transaction.remove(fileDetails);
+                transaction.add(R.id.file_details_container, new FileDetailFragment(null, null),
+                        FileDetailFragment.FTAG);
+                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.d(getClass().toString(), "onSaveInstanceState() start");
+        super.onSaveInstanceState(outState);
+        outState.putParcelable(FileDetailFragment.EXTRA_FILE, mCurrentDir);
+        if (mDualPane) {
+            FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+            if (fragment != null) {
+                OCFile file = fragment.getDisplayedFile();
+                if (file != null) {
+                    outState.putParcelable(FileDetailFragment.EXTRA_FILE, file);
+                }
+            }
+        }
+        Log.d(getClass().toString(), "onSaveInstanceState() end");
+    }
+
+    @Override
+    protected void onResume() {
+        Log.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();
+                }
+            }
+            
+            // 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_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.d(getClass().toString(), "onResume() end");
+    }
+
+    
+    @Override
+    protected void onPause() {
+        Log.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.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_ABOUT_APP: {
+            builder = new AlertDialog.Builder(this);
+            builder.setTitle(getString(R.string.about_title));
+            PackageInfo pkg;
+            try {
+                pkg = getPackageManager().getPackageInfo(getPackageName(), 0);
+                builder.setMessage(String.format(getString(R.string.about_message), getString(R.string.app_name), pkg.versionName));
+                builder.setIcon(android.R.drawable.ic_menu_info_details);
+                dialog = builder.create();
+            } catch (NameNotFoundException e) {
+                builder = null;
+                dialog = null;
+                Log.e(TAG, "Error while showing about dialog", e);
+            }
+            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: {
+            final String[] items = { getString(R.string.actionbar_upload_files),
+                    getString(R.string.actionbar_upload_from_apps), getString(R.string.actionbar_failed_instant_upload) };
+            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) {
+                        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.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.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);
+                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();
+                }
+            }
+        }
+        
+    }
+    
+    
+    /**
+     * Once the file download has finished -> update view
+     */
+    private class DownloadFinishReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
+            String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
+            boolean sameAccount = accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name);
+            boolean isDescendant = (mCurrentDir != null) && (downloadedRemotePath != null)
+                    && (downloadedRemotePath.startsWith(mCurrentDir.getRemotePath()));
+            if (sameAccount && isDescendant) {
+                OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager()
+                        .findFragmentById(R.id.fileList);
+                if (fileListFragment != null) {
+                    fileListFragment.listDirectory();
+                }
+            }
+        }
+    }
+    
+    
+    
+    
+    /**
+     * {@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
+            FileDetailFragment fileDetails = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+            if (fileDetails != null && !fileDetails.isEmpty()) {
+                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+                transaction.remove(fileDetails);
+                transaction.add(R.id.file_details_container, new FileDetailFragment(null, null),
+                        FileDetailFragment.FTAG);
+                transaction.commit();
+            }
+        }
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onFileClick(OCFile file) {
+        
+        // If we are on a large device -> update fragment
+        if (mDualPane) {
+            // 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'
+            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+            transaction
+                    .replace(R.id.file_details_container,
+                            new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)),
+                            FileDetailFragment.FTAG);
+            transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
+            transaction.commit();
+
+        } else { // small or medium screen device -> new Activity
+            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.d(TAG, "Download service connected");
+                mDownloaderBinder = (FileDownloaderBinder) service;
+            } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {
+                Log.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) {
+                FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(
+                        FileDetailFragment.FTAG);
+                if (fragment != null)
+                    fragment.updateFileDetails(false);
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName component) {
+            if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {
+                Log.d(TAG, "Download service disconnected");
+                mDownloaderBinder = null;
+            } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {
+                Log.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);
+        }
+    }
+
+
+    /**
+     * 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) {
+                FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(
+                        FileDetailFragment.FTAG);
+                if (details != null && removedFile.equals(details.getDisplayedFile())) {
+                    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 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) {
+                FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(
+                        FileDetailFragment.FTAG);
+                if (details != null && renamedFile.equals(details.getDisplayedFile())) {
+                    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) {
+            FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(
+                    FileDetailFragment.FTAG);
+            if (details != null && file.equals(details.getDisplayedFile())) {
+                if (downloading || uploading) {
+                    details.updateFileDetails(file, AccountUtils.getCurrentOwnCloudAccount(this));
+                } else {
+                    details.updateFileDetails(downloading || uploading);
+                }
+            }
+        }
+    }
+
+
+    
+
+
+}
diff --git a/src/com/owncloud/android/ui/activity/InstantUploadActivity.java b/src/com/owncloud/android/ui/activity/InstantUploadActivity.java
new file mode 100644 (file)
index 0000000..4325b8a
--- /dev/null
@@ -0,0 +1,436 @@
+/* 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 as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package com.owncloud.android.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;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.Gravity;
+import android.view.View;
+import android.view.View.OnClickListener;
+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.Toast;
+
+import com.owncloud.android.AccountUtils;
+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.files.services.InstantUploadService;
+
+/**
+ * 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 entrypoint for this activity is the 'Failed upload Notification" and a
+ * submenue underneath the 'Upload' menuentry
+ * 
+ * @author andomaex / Matthias Baumann
+ * 
+ *         This program is free software: you can redistribute it and/or modify
+ *         it under the terms of the GNU General Public License as published by
+ *         the Free Software Foundation, either version 3 of the License, or (at
+ *         your option) any later version.
+ * 
+ *         This program is distributed in the hope that it will be useful, but
+ *         WITHOUT ANY WARRANTY; without even the implied warranty of
+ *         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ *         General Public License for more de/
+ */
+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";
+    private static int MAX_LOAD_IMAGES = 5;
+    private int lastLoadImageIdx = 0;
+
+    private SparseArray<String> fileList = null;
+
+    @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());
+        CheckBox 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);
+                    fileList.put(lastLoadImageIdx, imp_path);
+                    LinearLayout rowLayout = getLinearLayout(lastLoadImageIdx);
+                    rowLayout.addView(getFileCheckbox(lastLoadImageIdx));
+                    rowLayout.addView(getImageButton(imp_path, lastLoadImageIdx));
+                    rowLayout.addView(getFileButton(imp_path, lastLoadImageIdx));
+                    listView.addView(rowLayout);
+                    Log.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.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.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.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.d(LOG_TAG, msg);
+                            startUpload(img_path);
+                        }
+
+                    }
+                } finally {
+                    // refresh the List
+                    listView.removeAllViews();
+                    loadListView(true);
+                }
+
+            }
+        };
+    }
+
+    /**
+     * 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.d(LOG_TAG, "Checkbox for " + checkbox.getId() + " was checked: " + to_be_delete);
+                        String img_path = fileList.get(checkbox.getId());
+                        Log.d(LOG_TAG, "Image-Path " + checkbox.getId() + " was checked: " + img_path);
+                        if (to_be_delete) {
+                            boolean deleted = dbh.removeIUPendingFile(img_path);
+                            Log.d(LOG_TAG, "removing " + checkbox.getId() + " was : " + deleted);
+
+                        }
+
+                    }
+                } finally {
+                    dbh.close();
+                    // refresh the List
+                    listView.removeAllViews();
+                    loadListView(true);
+                }
+
+            }
+        };
+    }
+
+    private LinearLayout getLinearLayout(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 Button getFileButton(final String img_path, int id) {
+        Button retryButton = new Button(this);
+        retryButton.setId(id);
+        retryButton.setText(img_path);
+        retryButton.setBackgroundResource(R.color.owncloud_white);
+        retryButton.setTextSize(8);
+        retryButton.setOnClickListener(getImageButtonOnClickListener(img_path));
+        return retryButton;
+    }
+
+    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.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.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.d(LOG_TAG, "loaded Bitmap Bytes: " + bitmap.getRowBytes());
+                imageButton.setImageBitmap(bitmap);
+            } else {
+                Log.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 = img_path.substring(img_path.lastIndexOf('/'), img_path.length());
+        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);
+            } 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, InstantUploadService.INSTANT_UPLOAD_DIR + "/" + 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.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;
+        }
+    }
+
+}
\ No newline at end of file