Merge branch 'develop' into loggingtool
authorDavid A. Velasco <dvelasco@solidgear.es>
Mon, 15 Apr 2013 11:12:04 +0000 (13:12 +0200)
committerDavid A. Velasco <dvelasco@solidgear.es>
Mon, 15 Apr 2013 11:12:04 +0000 (13:12 +0200)
Conflicts:
AndroidManifest.xml
res/menu/main_menu.xml
src/com/owncloud/android/datamodel/OCFile.java
src/com/owncloud/android/files/services/FileDownloader.java
src/com/owncloud/android/files/services/InstantUploadService.java
src/com/owncloud/android/operations/SynchronizeFileOperation.java
src/com/owncloud/android/operations/UploadFileOperation.java
src/com/owncloud/android/ui/activity/FileDetailActivity.java
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/activity/UploadFilesActivity.java
src/com/owncloud/android/ui/fragment/FileDetailFragment.java
src/com/owncloud/android/ui/fragment/OCFileListFragment.java
src/eu/alefzero/webdav/ChunkFromFileChannelRequestEntity.java
src/eu/alefzero/webdav/FileRequestEntity.java
src/eu/alefzero/webdav/WebdavClient.java

56 files changed:
AndroidManifest.xml
res/layout/log_item.xml [new file with mode: 0644]
res/layout/log_send_file.xml [new file with mode: 0644]
res/values/strings.xml
res/xml/preferences.xml
src/com/owncloud/android/Log_OC.java [new file with mode: 0644]
src/com/owncloud/android/Uploader.java
src/com/owncloud/android/authenticator/AccountAuthenticator.java
src/com/owncloud/android/datamodel/FileDataStorageManager.java
src/com/owncloud/android/datamodel/OCFile.java
src/com/owncloud/android/db/DbHandler.java
src/com/owncloud/android/extensions/ExtensionsAvailableDialog.java
src/com/owncloud/android/extensions/ExtensionsListActivity.java
src/com/owncloud/android/files/BootupBroadcastReceiver.java
src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java
src/com/owncloud/android/files/OwnCloudFileObserver.java
src/com/owncloud/android/files/services/FileDownloader.java
src/com/owncloud/android/files/services/FileObserverService.java
src/com/owncloud/android/files/services/FileUploader.java
src/com/owncloud/android/files/services/InstantUploadService.java
src/com/owncloud/android/location/LocationServiceLauncherReciever.java
src/com/owncloud/android/location/LocationUpdateService.java
src/com/owncloud/android/network/AdvancedSslSocketFactory.java
src/com/owncloud/android/network/AdvancedX509TrustManager.java
src/com/owncloud/android/network/OwnCloudClientUtils.java
src/com/owncloud/android/operations/ChunkedUploadFileOperation.java
src/com/owncloud/android/operations/ConnectionCheckOperation.java
src/com/owncloud/android/operations/DownloadFileOperation.java
src/com/owncloud/android/operations/RemoveFileOperation.java
src/com/owncloud/android/operations/RenameFileOperation.java
src/com/owncloud/android/operations/SynchronizeFileOperation.java
src/com/owncloud/android/operations/SynchronizeFolderOperation.java
src/com/owncloud/android/operations/UpdateOCVersionOperation.java
src/com/owncloud/android/operations/UploadFileOperation.java
src/com/owncloud/android/providers/FileContentProvider.java
src/com/owncloud/android/syncadapter/FileSyncAdapter.java
src/com/owncloud/android/ui/activity/AccountSelectActivity.java
src/com/owncloud/android/ui/activity/AuthenticatorActivity.java
src/com/owncloud/android/ui/activity/ConflictsResolveActivity.java
src/com/owncloud/android/ui/activity/ErrorsWhileCopyingHandlerActivity.java
src/com/owncloud/android/ui/activity/FileDetailActivity.java
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/activity/InstantUploadActivity.java
src/com/owncloud/android/ui/activity/LogHistoryActivity.java [new file with mode: 0644]
src/com/owncloud/android/ui/activity/Preferences.java
src/com/owncloud/android/ui/activity/UploadFilesActivity.java
src/com/owncloud/android/ui/adapter/LogListAdapter.java [new file with mode: 0644]
src/com/owncloud/android/ui/dialog/SslValidatorDialog.java
src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java
src/com/owncloud/android/ui/fragment/FileDetailFragment.java
src/com/owncloud/android/ui/fragment/LocalFileListFragment.java
src/com/owncloud/android/ui/fragment/OCFileListFragment.java
src/eu/alefzero/webdav/ChunkFromFileChannelRequestEntity.java
src/eu/alefzero/webdav/FileRequestEntity.java
src/eu/alefzero/webdav/WebdavClient.java
src/eu/alefzero/webdav/WebdavEntry.java

index e5e4a05..4570ea1 100644 (file)
-<?xml version="1.0" encoding="utf-8"?>\r
-<!-- \r
-  ownCloud Android client application\r
-\r
-  Copyright (C) 2012  Bartek Przybylski\r
-  Copyright (C) 2012-2013 ownCloud Inc.\r
-\r
-  This program is free software: you can redistribute it and/or modify\r
-  it under the terms of the GNU General Public License as published by\r
-  the Free Software Foundation, either version 2 of the License, or\r
-  (at your option) any later version.\r
-\r
-  This program is distributed in the hope that it will be useful,\r
-  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-  GNU General Public License for more details.\r
-\r
-  You should have received a copy of the GNU General Public License\r
-  along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
- -->\r
-<manifest package="com.owncloud.android"\r
-    android:versionCode="104000"\r
-    android:versionName="1.4.0" xmlns:android="http://schemas.android.com/apk/res/android">\r
-\r
-    <uses-permission android:name="android.permission.GET_ACCOUNTS" />\r
-    <uses-permission android:name="android.permission.USE_CREDENTIALS" />\r
-    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />\r
-    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />\r
-    <uses-permission android:name="android.permission.INTERNET" />\r
-    <uses-permission android:name="android.permission.WRITE_SETTINGS" />\r
-    <uses-permission android:name="android.permission.READ_SYNC_STATS" />\r
-    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />\r
-    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />\r
-    <uses-permission android:name="android.permission.BROADCAST_STICKY" />\r
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />\r
-    <uses-permission android:name="android.permission.READ_PHONE_STATE" />\r
-    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>\r
-    <uses-permission android:name="android.permission.WAKE_LOCK"/>\r
-    \r
-    <uses-sdk\r
-        android:minSdkVersion="8"\r
-        android:targetSdkVersion="13" />\r
-\r
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >\r
-    </uses-permission>\r
-\r
-    <application\r
-        android:icon="@drawable/icon"\r
-        android:label="@string/app_name"\r
-        android:theme="@style/Theme.ownCloud"> \r
-        <activity\r
-            android:name=".ui.activity.FileDisplayActivity"\r
-            android:label="@string/app_name">\r
-            <intent-filter>\r
-                <action android:name="android.intent.action.MAIN" />\r
-\r
-                <category android:name="android.intent.category.LAUNCHER" />\r
-            </intent-filter>\r
-        </activity>\r
-        <activity android:name=".ui.activity.UploadFilesActivity">\r
-        </activity>\r
-               <activity android:name=".ui.activity.InstantUploadActivity">\r
-        </activity>\r
-        <activity android:name=".ui.activity.FailedUploadActivity" android:theme="@android:style/Theme.Dialog" android:excludeFromRecents="true"/>\r
-        <activity android:name=".Uploader" >\r
-            <intent-filter>\r
-                <action android:name="android.intent.action.SEND" >\r
-                </action>\r
-\r
-                <category android:name="android.intent.category.DEFAULT" >\r
-                </category>\r
-\r
-                <data android:mimeType="*/*" >\r
-                </data>\r
-            </intent-filter>\r
-            <intent-filter>\r
-                <action android:name="android.intent.action.SEND_MULTIPLE" >\r
-                </action>\r
-\r
-                <category android:name="android.intent.category.DEFAULT" >\r
-                </category>\r
-\r
-                <data android:mimeType="*/*" >\r
-                </data>\r
-            </intent-filter>\r
-        </activity>\r
-        <activity\r
-            android:name=".ui.activity.Preferences"\r
-            android:theme="@style/Theme.ownCloud" >\r
-        </activity>\r
-        <activity android:name=".ui.activity.PreferencesNewSessionewSession" >\r
-        </activity>\r
-        \r
-               <activity       android:name="com.owncloud.android.ui.preview.PreviewImageActivity" />\r
-                       \r
-        <activity      android:name="com.owncloud.android.ui.preview.PreviewVideoActivity"\r
-                                       android:label="@string/app_name"\r
-                                       android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >\r
-               </activity>        \r
-\r
-        <service\r
-            android:name=".authenticator.AccountAuthenticatorService"\r
-            android:exported="true">\r
-            <intent-filter  android:priority="100">\r
-                <action android:name="android.accounts.AccountAuthenticator" />\r
-            </intent-filter>\r
-\r
-            <meta-data\r
-                android:name="android.accounts.AccountAuthenticator"\r
-                android:resource="@xml/authenticator" />\r
-        </service>\r
-        <service\r
-            android:name=".syncadapter.FileSyncService"\r
-            android:exported="true" >\r
-            <intent-filter>\r
-                <action android:name="android.content.SyncAdapter" />\r
-            </intent-filter>\r
-\r
-            <meta-data\r
-                android:name="android.content.SyncAdapter"\r
-                android:resource="@xml/syncadapter_files" />\r
-        </service>\r
-\r
-        <provider\r
-            android:name=".providers.FileContentProvider"\r
-            android:authorities="org.owncloud"\r
-            android:enabled="true"\r
-            android:exported="false"\r
-            android:label="@string/sync_string_files"\r
-            android:syncable="true" >\r
-        </provider>\r
-\r
-        <activity\r
-            android:name=".ui.activity.AuthenticatorActivity"\r
-            android:exported="true"\r
-            android:theme="@style/Theme.ownCloud.noActionBar" >\r
-            <intent-filter>\r
-                <action android:name="com.owncloud.android.workaround.accounts.CREATE" />\r
-                <category android:name="android.intent.category.DEFAULT" />\r
-            </intent-filter>\r
-        </activity>\r
-\r
-        <service android:name=".files.services.FileDownloader" />\r
-        <service android:name=".files.services.FileUploader" />\r
-        <service android:name=".media.MediaService" />\r
-\r
-        <activity android:name=".ui.activity.FileDetailActivity" />\r
-        <activity android:name=".ui.activity.PinCodeActivity" />\r
-        <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"/>\r
-        <activity android:name=".ui.activity.GenericExplanationActivity"/>\r
-        <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>\r
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 
+  ownCloud Android client application
+
+  Copyright (C) 2012  Bartek Przybylski
+  Copyright (C) 2012-2013 ownCloud Inc.
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License 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/>.
+ -->
+<manifest package="com.owncloud.android"
+    android:versionCode="104000"
+    android:versionName="1.4.0" xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
+    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
+    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.READ_SYNC_STATS" />
+    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
+    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
+    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
+    <uses-permission android:name="android.permission.WAKE_LOCK"/>
+    
+    <uses-sdk
+        android:minSdkVersion="8"
+        android:targetSdkVersion="13" />
+
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
+    </uses-permission>
+
+    <application
+        android:icon="@drawable/icon"
+        android:label="@string/app_name"
+        android:theme="@style/Theme.ownCloud"> 
+        <activity
+            android:name=".ui.activity.FileDisplayActivity"
+            android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".ui.activity.UploadFilesActivity">
+        </activity>
+               <activity android:name=".ui.activity.InstantUploadActivity">
+        </activity>
+        <activity android:name=".ui.activity.FailedUploadActivity" android:theme="@android:style/Theme.Dialog" android:excludeFromRecents="true"/>
+        <activity android:name=".Uploader" >
+            <intent-filter>
+                <action android:name="android.intent.action.SEND" >
+                </action>
+
+                <category android:name="android.intent.category.DEFAULT" >
+                </category>
+
+                <data android:mimeType="*/*" >
+                </data>
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.SEND_MULTIPLE" >
+                </action>
+
+                <category android:name="android.intent.category.DEFAULT" >
+                </category>
+
+                <data android:mimeType="*/*" >
+                </data>
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".ui.activity.Preferences"
+            android:theme="@style/Theme.ownCloud" >
+        </activity>
+        <activity android:name=".ui.activity.PreferencesNewSessionewSession" >
+        </activity>
+        
+               <activity       android:name="com.owncloud.android.ui.preview.PreviewImageActivity" />
+                       
+        <activity      android:name="com.owncloud.android.ui.preview.PreviewVideoActivity"
+                                       android:label="@string/app_name"
+                                       android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
+               </activity>        
+
+        <service
+            android:name=".authenticator.AccountAuthenticatorService"
+            android:exported="true">
+            <intent-filter  android:priority="100">
+                <action android:name="android.accounts.AccountAuthenticator" />
+            </intent-filter>
+
+            <meta-data
+                android:name="android.accounts.AccountAuthenticator"
+                android:resource="@xml/authenticator" />
+        </service>
+        <service
+            android:name=".syncadapter.FileSyncService"
+            android:exported="true" >
+            <intent-filter>
+                <action android:name="android.content.SyncAdapter" />
+            </intent-filter>
+
+            <meta-data
+                android:name="android.content.SyncAdapter"
+                android:resource="@xml/syncadapter_files" />
+        </service>
+
+        <provider
+            android:name=".providers.FileContentProvider"
+            android:authorities="org.owncloud"
+            android:enabled="true"
+            android:exported="false"
+            android:label="@string/sync_string_files"
+            android:syncable="true" >
+        </provider>
+
+        <activity
+            android:name=".ui.activity.AuthenticatorActivity"
+            android:exported="true"
+            android:theme="@style/Theme.ownCloud.noActionBar" >
+            <intent-filter>
+                <action android:name="com.owncloud.android.workaround.accounts.CREATE" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <service android:name=".files.services.FileDownloader" />
+        <service android:name=".files.services.FileUploader" />
+        <service android:name=".media.MediaService" />
+        
+        <activity android:name=".ui.activity.FileDetailActivity" />
+        <activity android:name=".ui.activity.PinCodeActivity" />
+        <activity android:name=".extensions.ExtensionsAvailableActivity"></activity>
+        <activity android:name=".extensions.ExtensionsListActivity"></activity>
+        <activity android:name=".ui.activity.AccountSelectActivity" android:uiOptions="none" android:label="@string/prefs_accounts"></activity>
+        <activity android:name=".ui.activity.ConflictsResolveActivity"/>
+        <activity android:name=".ui.activity.GenericExplanationActivity"/>
+        <activity android:name=".ui.activity.ErrorsWhileCopyingHandlerActivity"/>
+        
+        <activity android:name=".ui.activity.LogHistoryActivity"/>
         
         <service android:name=".files.services.InstantUploadService" />
-        <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>\r
-            <intent-filter>\r
-                <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>\r
-            </intent-filter>\r
-        </receiver>\r
-        <receiver android:name=".files.BootupBroadcastReceiver">\r
-            <intent-filter>\r
-                <action android:name="android.intent.action.BOOT_COMPLETED"/>\r
-            </intent-filter>\r
-        </receiver>\r
-        <service android:name=".files.services.FileObserverService"/>\r
-    </application>\r
-\r
-</manifest>\r
+        <receiver android:name=".files.InstantUploadBroadcastReceiver">
+            <intent-filter>
+                <action android:name="com.android.camera.NEW_PICTURE" />
+                <data android:mimeType="image/*" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
+            </intent-filter>
+        </receiver>
+        <receiver android:name=".files.BootupBroadcastReceiver">
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED"/>
+            </intent-filter>
+        </receiver>
+        <service android:name=".files.services.FileObserverService"/>
+    </application>
+    
+</manifest>
diff --git a/res/layout/log_item.xml b/res/layout/log_item.xml
new file mode 100644 (file)
index 0000000..d9326ff
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal" >
+    
+     <TextView android:id="@+id/log_item_single"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:gravity="center_vertical"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentBottom="true"
+        android:textStyle="bold"
+        android:textSize="22dp"
+        android:textColor="#000000"
+        android:layout_marginTop="5dp"
+        android:layout_marginBottom="5dp" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/log_send_file.xml b/res/layout/log_send_file.xml
new file mode 100644 (file)
index 0000000..ddeac69
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+ <LinearLayout 
+        xmlns:android="http://schemas.android.com/apk/res/android"
+         android:orientation="vertical"
+         android:layout_width="match_parent"
+         android:layout_height="match_parent"
+         android:paddingLeft="8dp"
+         android:paddingRight="8dp">
+      
+
+     <ListView         android:id="@android:id/list"
+                       android:layout_width="match_parent"
+                       android:layout_height="wrap_content"
+               />
+
+     <TextView         android:id="@android:id/empty"
+                       android:layout_width="match_parent"
+                       android:layout_height="wrap_content"
+                       android:background="#FF0000"
+                       android:text="No data"/>
+     <LinearLayout 
+         android:orientation="vertical"
+         android:layout_width="match_parent"
+         android:layout_height="wrap_content"
+         android:gravity="bottom">
+        
+     <Button           android:id="@+id/deleteLogHistoryButton"
+                       android:layout_width="match_parent"
+                       android:layout_height="wrap_content"
+                       android:text="@string/prefs_log_delete_history_button"/>
+     
+     </LinearLayout>
+     
+ </LinearLayout>
index f54a5d5..415041b 100644 (file)
@@ -14,7 +14,8 @@
     <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="about_android">Android App </string>
+    <string name="about_version">version: </string>
     <string name="actionbar_sync">Refresh</string>
     <string name="actionbar_upload">Upload</string>
     <string name="actionbar_upload_from_apps">Content from other apps</string>
     <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="prefs_log_title">Enable Logging</string>
+    <string name="prefs_log_summary">This is used to log problems</string>
+    <string name="prefs_log_title_history">Logging History</string>
+    <string name="prefs_log_summary_history">This shows the recorded logs</string>
+    <string name="prefs_log_delete_history_button">Delete History</string>
+    
     <string name="auth_host_url">URL</string>
     <string name="auth_username">Username</string>
     <string name="auth_password">Password</string>
         <item>60</item>
     </string-array>
 
-    <string name="auth_trying_to_login">Trying to login…</string>
+    <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_connect_anyway">Connect anyway</string>
     <string name="auth_nossl_plain_ok_title">Secure connection unavailable.</string>
     <string name="auth_nossl_plain_ok_message">The Application cannot establish a secure connection to the server. A non secure connection is available. You may continue or cancel.</string>
     <string name="auth_connection_established">Connection established</string>
-    <string name="auth_testing_connection">Testing connection…</string>
+    <string name="auth_testing_connection">Testing connection...</string>
     <string name="auth_not_configured_title">Malformed server configuration</string>
     <string name="auth_not_configured_message">It seems that your server instance is not correctly configured. Contact your administrator for more details.</string>
     <string name="auth_unknown_error_title">Unknown error occurred!</string>
index 3b168f5..ced90dd 100644 (file)
     <CheckBoxPreference android:key="instant_uploading" 
                         android:title="@string/prefs_instant_upload"  
                         android:summary="@string/prefs_instant_upload_summary"/>
-    <CheckBoxPreference android:dependency="instant_uploading" android:disableDependentsState="true" android:title="@string/instant_upload_on_wifi" android:key="instant_upload_on_wifi"/>
-    
+    <CheckBoxPreference android:dependency="instant_uploading" 
+                                       android:disableDependentsState="true" 
+                                       android:title="@string/instant_upload_on_wifi" 
+                                       android:key="instant_upload_on_wifi"/>
+    <CheckBoxPreference android:key="log_to_file" 
+                        android:title="@string/prefs_log_title"  
+                        android:summary="@string/prefs_log_summary"/>
+       <Preference             android:key="log_history" 
+                        android:title="@string/prefs_log_title_history"  
+                        android:summary="@string/prefs_log_summary_history"/>
+       <Preference             android:id="@+id/about_app" 
+                                       android:title="@string/about_title" 
+                                       android:key="about_app" />
        </PreferenceCategory>
     
 
diff --git a/src/com/owncloud/android/Log_OC.java b/src/com/owncloud/android/Log_OC.java
new file mode 100644 (file)
index 0000000..1e2937c
--- /dev/null
@@ -0,0 +1,127 @@
+package com.owncloud.android;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+import android.util.Log;
+
+
+
+public class Log_OC {
+    
+
+    private static boolean isEnabled = false;
+    private static File logFile;
+    private static File folder;
+    private static BufferedWriter buf;  
+    
+    public static void i(String TAG, String message){
+        // Printing the message to LogCat console
+        Log.i(TAG, message);
+        // Write the log message to the file
+        appendLog(TAG+" : "+message);
+    }
+
+    public static void d(String TAG, String message){
+        Log.d(TAG, message);
+        appendLog(TAG+" : "+message);
+    }
+    public static void d(String TAG, String message, Exception e) {
+        Log.d(TAG, message, e);
+        appendLog(TAG+" : "+ message+" Exception : "+e.getStackTrace());
+    }
+    public static void e(String TAG, String message){
+        Log.e(TAG, message);
+        appendLog(TAG+" : "+message);
+    }
+    
+    public static void e(String TAG, String message, Throwable e) {
+        Log.e(TAG, message, e);
+        appendLog(TAG+" : "+ message+" Exception : "+e.getStackTrace());
+    }
+    
+    public static void v(String TAG, String message){
+        Log.v(TAG, message);
+        appendLog(TAG+" : "+message);
+    }
+    
+    public static void w(String TAG, String message) {
+        Log.w(TAG,message); 
+        appendLog(TAG+" : "+message);
+    }
+    
+    public static void wtf(String TAG, String message) {
+        Log.wtf(TAG,message); 
+        appendLog(TAG+" : "+message);
+    }
+    
+    public static void startLogging(String logPath) {
+        folder = new File(logPath);
+        logFile = new File(folder+File.separator+"log.txt");
+        
+        if (!folder.exists()) {
+            folder.mkdirs();
+        }
+        if (logFile.exists()) {
+            logFile.delete();
+        }
+        try { 
+            logFile.createNewFile();
+            buf = new BufferedWriter(new FileWriter(logFile, true));
+            isEnabled = true;
+            appendPhoneInfo();
+        }catch (IOException e){ 
+            e.printStackTrace(); 
+        } 
+    }
+    
+    public static void stopLogging() {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss",Locale.getDefault());
+        String currentDateandTime = sdf.format(new Date());
+        if (logFile != null) {
+            logFile.renameTo(new File(folder+File.separator+"Owncloud_"+currentDateandTime+".log"));
+          
+            isEnabled = false;
+            try {
+                buf.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            } 
+        
+        }
+        
+    }
+    
+    private static void appendPhoneInfo() {
+        appendLog("Model : " + android.os.Build.MODEL);
+        appendLog("Brand : " + android.os.Build.BRAND);
+        appendLog("Product : " + android.os.Build.PRODUCT);
+        appendLog("Device : " + android.os.Build.DEVICE);
+        appendLog("Version-Codename : " + android.os.Build.VERSION.CODENAME);
+        appendLog("Version-Release : " + android.os.Build.VERSION.RELEASE);
+    }
+    
+    private static void appendLog(String text) { 
+        if (isEnabled) {
+           try { 
+               buf.append(text); 
+               buf.newLine(); 
+           } catch (IOException e) { 
+               e.printStackTrace(); 
+        } 
+    }
+}
+
+    
+   
+
+  
+
+   
+   
+}
index 6f9dc6d..4383089 100644 (file)
-/* ownCloud Android client application\r
- *   Copyright (C) 2012  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- *   This program is free software: you can redistribute it and/or modify\r
- *   it under the terms of the GNU General Public License as published by\r
- *   the Free Software Foundation, either version 2 of the License, or\r
- *   (at your option) any later version.\r
- *\r
- *   This program is distributed in the hope that it will be useful,\r
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- *   GNU General Public License for more details.\r
- *\r
- *   You should have received a copy of the GNU General Public License\r
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-package com.owncloud.android;\r
-\r
-import java.io.File;\r
-import java.util.ArrayList;\r
-import java.util.HashMap;\r
-import java.util.LinkedList;\r
-import java.util.List;\r
-import java.util.Stack;\r
-import java.util.Vector;\r
-\r
-import com.owncloud.android.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.FileUploader;\r
-import com.owncloud.android.network.OwnCloudClientUtils;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountManager;\r
-import android.app.AlertDialog;\r
-import android.app.AlertDialog.Builder;\r
-import android.app.Dialog;\r
-import android.app.ListActivity;\r
-import android.app.ProgressDialog;\r
-import android.content.Context;\r
-import android.content.DialogInterface;\r
-import android.content.DialogInterface.OnCancelListener;\r
-import android.content.DialogInterface.OnClickListener;\r
-import android.content.Intent;\r
-import android.database.Cursor;\r
-import android.net.Uri;\r
-import android.os.Bundle;\r
-import android.os.Parcelable;\r
-import android.provider.MediaStore.Images.Media;\r
-import android.util.Log;\r
-import android.view.View;\r
-import android.view.Window;\r
-import android.widget.AdapterView;\r
-import android.widget.AdapterView.OnItemClickListener;\r
-import android.widget.Button;\r
-import android.widget.EditText;\r
-import android.widget.SimpleAdapter;\r
-import android.widget.Toast;\r
-\r
-import com.owncloud.android.R;\r
-import eu.alefzero.webdav.WebdavClient;\r
-\r
-/**\r
- * This can be used to upload things to an ownCloud instance.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener {\r
-    private static final String TAG = "ownCloudUploader";\r
-\r
-    private Account mAccount;\r
-    private AccountManager mAccountManager;\r
-    private Stack<String> mParents;\r
-    private ArrayList<Parcelable> mStreamsToUpload;\r
-    private boolean mCreateDir;\r
-    private String mUploadPath;\r
-    private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE };\r
-    private DataStorageManager mStorageManager;\r
-    private OCFile mFile;\r
-\r
-    private final static int DIALOG_NO_ACCOUNT = 0;\r
-    private final static int DIALOG_WAITING = 1;\r
-    private final static int DIALOG_NO_STREAM = 2;\r
-    private final static int DIALOG_MULTIPLE_ACCOUNT = 3;\r
-    //private final static int DIALOG_GET_DIRNAME = 4;\r
-\r
-    private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;\r
-\r
-    @Override\r
-    protected void onCreate(Bundle savedInstanceState) {\r
-        super.onCreate(savedInstanceState);\r
-        getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
-        mParents = new Stack<String>();\r
-        mParents.add("");\r
-        /*if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {\r
-            prepareStreamsToUpload();*/\r
-        if (prepareStreamsToUpload()) {\r
-            mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);\r
-            Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);\r
-            if (accounts.length == 0) {\r
-                Log.i(TAG, "No ownCloud account is available");\r
-                showDialog(DIALOG_NO_ACCOUNT);\r
-            } else if (accounts.length > 1) {\r
-                Log.i(TAG, "More then one ownCloud is available");\r
-                showDialog(DIALOG_MULTIPLE_ACCOUNT);\r
-            } else {\r
-                mAccount = accounts[0];\r
-                mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());\r
-                populateDirectoryList();\r
-            }\r
-        } else {\r
-            showDialog(DIALOG_NO_STREAM);\r
-        }\r
-    }\r
-    \r
-    @Override\r
-    protected Dialog onCreateDialog(final int id) {\r
-        final AlertDialog.Builder builder = new Builder(this);\r
-        switch (id) {\r
-        case DIALOG_WAITING:\r
-            ProgressDialog pDialog = new ProgressDialog(this);\r
-            pDialog.setIndeterminate(false);\r
-            pDialog.setCancelable(false);\r
-            pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading));\r
-            return pDialog;\r
-        case DIALOG_NO_ACCOUNT:\r
-            builder.setIcon(android.R.drawable.ic_dialog_alert);\r
-            builder.setTitle(R.string.uploader_wrn_no_account_title);\r
-            builder.setMessage(String.format(getString(R.string.uploader_wrn_no_account_text), getString(R.string.app_name)));\r
-            builder.setCancelable(false);\r
-            builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {\r
-                @Override\r
-                public void onClick(DialogInterface dialog, int which) {\r
-                    if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {\r
-                        // using string value since in API7 this\r
-                        // constatn is not defined\r
-                        // in API7 < this constatant is defined in\r
-                        // Settings.ADD_ACCOUNT_SETTINGS\r
-                        // and Settings.EXTRA_AUTHORITIES\r
-                        Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");\r
-                        intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
-                        startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);\r
-                    } else {\r
-                        // since in API7 there is no direct call for\r
-                        // account setup, so we need to\r
-                        // show our own AccountSetupAcricity, get\r
-                        // desired results and setup\r
-                        // everything for ourself\r
-                        Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);\r
-                        startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);\r
-                    }\r
-                }\r
-            });\r
-            builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {\r
-                @Override\r
-                public void onClick(DialogInterface dialog, int which) {\r
-                    finish();\r
-                }\r
-            });\r
-            return builder.create();\r
-        /*case DIALOG_GET_DIRNAME:\r
-            final EditText dirName = new EditText(getBaseContext());\r
-            builder.setView(dirName);\r
-            builder.setTitle(R.string.uploader_info_dirname);\r
-            String pathToUpload;\r
-            if (mParents.empty()) {\r
-                pathToUpload = "/";\r
-            } else {\r
-                mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), null,\r
-                        null, null, null);\r
-                mCursor.moveToFirst();\r
-                pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH))\r
-                        + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20");   // TODO don't make this ; use WebdavUtils.encode in the right moment\r
-            }\r
-            a a = new a(pathToUpload, dirName);\r
-            builder.setPositiveButton(R.string.common_ok, a);\r
-            builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {\r
-                public void onClick(DialogInterface dialog, int which) {\r
-                    dialog.cancel();\r
-                }\r
-            });\r
-            return builder.create();*/\r
-        case DIALOG_MULTIPLE_ACCOUNT:\r
-            CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length];\r
-            for (int i = 0; i < ac.length; ++i) {\r
-                ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name;\r
-            }\r
-            builder.setTitle(R.string.common_choose_account);\r
-            builder.setItems(ac, new OnClickListener() {\r
-                @Override\r
-                public void onClick(DialogInterface dialog, int which) {\r
-                    mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which];\r
-                    mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());\r
-                    populateDirectoryList();\r
-                }\r
-            });\r
-            builder.setCancelable(true);\r
-            builder.setOnCancelListener(new OnCancelListener() {\r
-                @Override\r
-                public void onCancel(DialogInterface dialog) {\r
-                    dialog.cancel();\r
-                    finish();\r
-                }\r
-            });\r
-            return builder.create();\r
-        case DIALOG_NO_STREAM:\r
-            builder.setIcon(android.R.drawable.ic_dialog_alert);\r
-            builder.setTitle(R.string.uploader_wrn_no_content_title);\r
-            builder.setMessage(R.string.uploader_wrn_no_content_text);\r
-            builder.setCancelable(false);\r
-            builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {\r
-                @Override\r
-                public void onClick(DialogInterface dialog, int which) {\r
-                    finish();\r
-                }\r
-            });\r
-            return builder.create();\r
-        default:\r
-            throw new IllegalArgumentException("Unknown dialog id: " + id);\r
-        }\r
-    }\r
-\r
-    class a implements OnClickListener {\r
-        String mPath;\r
-        EditText mDirname;\r
-\r
-        public a(String path, EditText dirname) {\r
-            mPath = path; \r
-            mDirname = dirname;\r
-        }\r
-\r
-        @Override\r
-        public void onClick(DialogInterface dialog, int which) {\r
-            Uploader.this.mUploadPath = mPath + mDirname.getText().toString();\r
-            Uploader.this.mCreateDir = true;\r
-            uploadFiles();\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void onBackPressed() {\r
-\r
-        if (mParents.size() <= 1) {\r
-            super.onBackPressed();\r
-            return;\r
-        } else {\r
-            mParents.pop();\r
-            populateDirectoryList();\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\r
-        // click on folder in the list\r
-        Log.d(TAG, "on item click");\r
-        Vector<OCFile> tmpfiles = mStorageManager.getDirectoryContent(mFile);\r
-        if (tmpfiles.size() <= 0) return;\r
-        // filter on dirtype\r
-        Vector<OCFile> files = new Vector<OCFile>();\r
-        for (OCFile f : tmpfiles)\r
-            if (f.isDirectory())\r
-                files.add(f);\r
-        if (files.size() < position) {\r
-            throw new IndexOutOfBoundsException("Incorrect item selected");\r
-        }\r
-        mParents.push(files.get(position).getFileName());\r
-        populateDirectoryList();\r
-    }\r
-\r
-    @Override\r
-    public void onClick(View v) {\r
-        // click on button\r
-        switch (v.getId()) {\r
-        case R.id.uploader_choose_folder:\r
-            mUploadPath = "";   // first element in mParents is root dir, represented by ""; init mUploadPath with "/" results in a "//" prefix\r
-            for (String p : mParents)\r
-                mUploadPath += p + OCFile.PATH_SEPARATOR;\r
-            Log.d(TAG, "Uploading file to dir " + mUploadPath);\r
-\r
-            uploadFiles();\r
-\r
-            break;\r
-        /*case android.R.id.button1: // dynamic action for create aditional dir\r
-            showDialog(DIALOG_GET_DIRNAME);\r
-            break;*/\r
-        default:\r
-            throw new IllegalArgumentException("Wrong element clicked");\r
-        }\r
-    }\r
-\r
-    @Override\r
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\r
-        super.onActivityResult(requestCode, resultCode, data);\r
-        Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);\r
-        if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {\r
-            dismissDialog(DIALOG_NO_ACCOUNT);\r
-            if (resultCode == RESULT_CANCELED) {\r
-                finish();\r
-            }\r
-            Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE);\r
-            if (accounts.length == 0) {\r
-                showDialog(DIALOG_NO_ACCOUNT);\r
-            } else {\r
-                // there is no need for checking for is there more then one\r
-                // account at this point\r
-                // since account setup can set only one account at time\r
-                mAccount = accounts[0];\r
-                populateDirectoryList();\r
-            }\r
-        }\r
-    }\r
-\r
-    private void populateDirectoryList() {\r
-        setContentView(R.layout.uploader_layout);\r
-\r
-        String full_path = "";\r
-        for (String a : mParents)\r
-            full_path += a + "/";\r
-        \r
-        Log.d(TAG, "Populating view with content of : " + full_path);\r
-        \r
-        mFile = mStorageManager.getFileByPath(full_path);\r
-        if (mFile != null) {\r
-            Vector<OCFile> files = mStorageManager.getDirectoryContent(mFile);\r
-            List<HashMap<String, Object>> data = new LinkedList<HashMap<String,Object>>();\r
-            for (OCFile f : files) {\r
-                HashMap<String, Object> h = new HashMap<String, Object>();\r
-                if (f.isDirectory()) {\r
-                    h.put("dirname", f.getFileName());\r
-                    data.add(h);\r
-                }\r
-            }\r
-            SimpleAdapter sa = new SimpleAdapter(this,\r
-                                                data,\r
-                                                R.layout.uploader_list_item_layout,\r
-                                                new String[] {"dirname"},\r
-                                                new int[] {R.id.textView1});\r
-            setListAdapter(sa);\r
-            Button btn = (Button) findViewById(R.id.uploader_choose_folder);\r
-            btn.setOnClickListener(this);\r
-            getListView().setOnItemClickListener(this);\r
-        }\r
-    }\r
-\r
-    private boolean prepareStreamsToUpload() {\r
-        if (getIntent().getAction().equals(Intent.ACTION_SEND)) {\r
-            mStreamsToUpload = new ArrayList<Parcelable>();\r
-            mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));\r
-        } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {\r
-            mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);\r
-        }\r
-        return (mStreamsToUpload != null && mStreamsToUpload.get(0) != null);\r
-    }\r
-\r
-    public void uploadFiles() {\r
-        try {\r
-            WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext());\r
-\r
-            // create last directory in path if necessary\r
-            if (mCreateDir) {\r
-                wdc.createDirectory(mUploadPath);\r
-            }\r
-\r
-            String[] local = new String[mStreamsToUpload.size()], remote = new String[mStreamsToUpload.size()];\r
-\r
-            for (int i = 0; i < mStreamsToUpload.size(); ++i) {\r
-                Uri uri = (Uri) mStreamsToUpload.get(i);\r
-                if (uri.getScheme().equals("content")) {\r
-                    Cursor c = getContentResolver().query((Uri) mStreamsToUpload.get(i),\r
-                                                      CONTENT_PROJECTION,\r
-                                                      null,\r
-                                                      null,\r
-                                                      null);\r
-\r
-                    if (!c.moveToFirst())\r
-                        continue;\r
-\r
-                    final String display_name = c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),\r
-                                data = c.getString(c.getColumnIndex(Media.DATA));\r
-                    local[i] = data;\r
-                    remote[i] = mUploadPath + display_name;\r
-                } else if (uri.getScheme().equals("file")) {\r
-                    final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme() + "://", ""));\r
-                    local[i] = file.getAbsolutePath();\r
-                    remote[i] = mUploadPath + file.getName();\r
-                }\r
-\r
-            }\r
-            Intent intent = new Intent(getApplicationContext(), FileUploader.class);\r
-            intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);\r
-            intent.putExtra(FileUploader.KEY_LOCAL_FILE, local);\r
-            intent.putExtra(FileUploader.KEY_REMOTE_FILE, remote);\r
-            intent.putExtra(FileUploader.KEY_ACCOUNT, mAccount);\r
-            startService(intent);\r
-            finish();\r
-            \r
-        } catch (SecurityException e) {\r
-            String message = String.format(getString(R.string.uploader_error_forbidden_content), getString(R.string.app_name));\r
-            Toast.makeText(this, message, Toast.LENGTH_LONG).show();            \r
-        }\r
-    }\r
-\r
-}\r
+/* ownCloud Android client application
+ *   Copyright (C) 2012  Bartek Przybylski
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License 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;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Stack;
+import java.util.Vector;
+
+import com.owncloud.android.authenticator.AccountAuthenticator;
+import com.owncloud.android.datamodel.DataStorageManager;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.network.OwnCloudClientUtils;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.app.Dialog;
+import android.app.ListActivity;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnCancelListener;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.provider.MediaStore.Images.Media;
+import android.util.Log;
+import android.view.View;
+import android.view.Window;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.SimpleAdapter;
+import android.widget.Toast;
+
+import com.owncloud.android.R;
+import eu.alefzero.webdav.WebdavClient;
+
+/**
+ * This can be used to upload things to an ownCloud instance.
+ * 
+ * @author Bartek Przybylski
+ * 
+ */
+public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener {
+    private static final String TAG = "ownCloudUploader";
+
+    private Account mAccount;
+    private AccountManager mAccountManager;
+    private Stack<String> mParents;
+    private ArrayList<Parcelable> mStreamsToUpload;
+    private boolean mCreateDir;
+    private String mUploadPath;
+    private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE };
+    private DataStorageManager mStorageManager;
+    private OCFile mFile;
+
+    private final static int DIALOG_NO_ACCOUNT = 0;
+    private final static int DIALOG_WAITING = 1;
+    private final static int DIALOG_NO_STREAM = 2;
+    private final static int DIALOG_MULTIPLE_ACCOUNT = 3;
+    //private final static int DIALOG_GET_DIRNAME = 4;
+
+    private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+        mParents = new Stack<String>();
+        mParents.add("");
+        /*if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {
+            prepareStreamsToUpload();*/
+        if (prepareStreamsToUpload()) {
+            mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE);
+            Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);
+            if (accounts.length == 0) {
+                Log_OC.i(TAG, "No ownCloud account is available");
+                showDialog(DIALOG_NO_ACCOUNT);
+            } else if (accounts.length > 1) {
+                Log_OC.i(TAG, "More then one ownCloud is available");
+                showDialog(DIALOG_MULTIPLE_ACCOUNT);
+            } else {
+                mAccount = accounts[0];
+                mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
+                populateDirectoryList();
+            }
+        } else {
+            showDialog(DIALOG_NO_STREAM);
+        }
+    }
+    
+    @Override
+    protected Dialog onCreateDialog(final int id) {
+        final AlertDialog.Builder builder = new Builder(this);
+        switch (id) {
+        case DIALOG_WAITING:
+            ProgressDialog pDialog = new ProgressDialog(this);
+            pDialog.setIndeterminate(false);
+            pDialog.setCancelable(false);
+            pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading));
+            return pDialog;
+        case DIALOG_NO_ACCOUNT:
+            builder.setIcon(android.R.drawable.ic_dialog_alert);
+            builder.setTitle(R.string.uploader_wrn_no_account_title);
+            builder.setMessage(String.format(getString(R.string.uploader_wrn_no_account_text), getString(R.string.app_name)));
+            builder.setCancelable(false);
+            builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {
+                        // using string value since in API7 this
+                        // constatn is not defined
+                        // in API7 < this constatant is defined in
+                        // Settings.ADD_ACCOUNT_SETTINGS
+                        // and Settings.EXTRA_AUTHORITIES
+                        Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");
+                        intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });
+                        startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
+                    } else {
+                        // since in API7 there is no direct call for
+                        // account setup, so we need to
+                        // show our own AccountSetupAcricity, get
+                        // desired results and setup
+                        // everything for ourself
+                        Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);
+                        startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
+                    }
+                }
+            });
+            builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    finish();
+                }
+            });
+            return builder.create();
+        /*case DIALOG_GET_DIRNAME:
+            final EditText dirName = new EditText(getBaseContext());
+            builder.setView(dirName);
+            builder.setTitle(R.string.uploader_info_dirname);
+            String pathToUpload;
+            if (mParents.empty()) {
+                pathToUpload = "/";
+            } else {
+                mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), null,
+                        null, null, null);
+                mCursor.moveToFirst();
+                pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH))
+                        + mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20");   // TODO don't make this ; use WebdavUtils.encode in the right moment
+            }
+            a a = new a(pathToUpload, dirName);
+            builder.setPositiveButton(R.string.common_ok, a);
+            builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {
+                public void onClick(DialogInterface dialog, int which) {
+                    dialog.cancel();
+                }
+            });
+            return builder.create();*/
+        case DIALOG_MULTIPLE_ACCOUNT:
+            CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length];
+            for (int i = 0; i < ac.length; ++i) {
+                ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name;
+            }
+            builder.setTitle(R.string.common_choose_account);
+            builder.setItems(ac, new OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which];
+                    mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
+                    populateDirectoryList();
+                }
+            });
+            builder.setCancelable(true);
+            builder.setOnCancelListener(new OnCancelListener() {
+                @Override
+                public void onCancel(DialogInterface dialog) {
+                    dialog.cancel();
+                    finish();
+                }
+            });
+            return builder.create();
+        case DIALOG_NO_STREAM:
+            builder.setIcon(android.R.drawable.ic_dialog_alert);
+            builder.setTitle(R.string.uploader_wrn_no_content_title);
+            builder.setMessage(R.string.uploader_wrn_no_content_text);
+            builder.setCancelable(false);
+            builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    finish();
+                }
+            });
+            return builder.create();
+        default:
+            throw new IllegalArgumentException("Unknown dialog id: " + id);
+        }
+    }
+
+    class a implements OnClickListener {
+        String mPath;
+        EditText mDirname;
+
+        public a(String path, EditText dirname) {
+            mPath = path; 
+            mDirname = dirname;
+        }
+
+        @Override
+        public void onClick(DialogInterface dialog, int which) {
+            Uploader.this.mUploadPath = mPath + mDirname.getText().toString();
+            Uploader.this.mCreateDir = true;
+            uploadFiles();
+        }
+    }
+
+    @Override
+    public void onBackPressed() {
+
+        if (mParents.size() <= 1) {
+            super.onBackPressed();
+            return;
+        } else {
+            mParents.pop();
+            populateDirectoryList();
+        }
+    }
+
+    @Override
+    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+        // click on folder in the list
+        Log_OC.d(TAG, "on item click");
+        Vector<OCFile> tmpfiles = mStorageManager.getDirectoryContent(mFile);
+        if (tmpfiles.size() <= 0) return;
+        // filter on dirtype
+        Vector<OCFile> files = new Vector<OCFile>();
+        for (OCFile f : tmpfiles)
+            if (f.isDirectory())
+                files.add(f);
+        if (files.size() < position) {
+            throw new IndexOutOfBoundsException("Incorrect item selected");
+        }
+        mParents.push(files.get(position).getFileName());
+        populateDirectoryList();
+    }
+
+    @Override
+    public void onClick(View v) {
+        // click on button
+        switch (v.getId()) {
+        case R.id.uploader_choose_folder:
+            mUploadPath = "";   // first element in mParents is root dir, represented by ""; init mUploadPath with "/" results in a "//" prefix
+            for (String p : mParents)
+                mUploadPath += p + OCFile.PATH_SEPARATOR;
+            Log_OC.d(TAG, "Uploading file to dir " + mUploadPath);
+
+            uploadFiles();
+
+            break;
+        /*case android.R.id.button1: // dynamic action for create aditional dir
+            showDialog(DIALOG_GET_DIRNAME);
+            break;*/
+        default:
+            throw new IllegalArgumentException("Wrong element clicked");
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        Log_OC.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);
+        if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {
+            dismissDialog(DIALOG_NO_ACCOUNT);
+            if (resultCode == RESULT_CANCELED) {
+                finish();
+            }
+            Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE);
+            if (accounts.length == 0) {
+                showDialog(DIALOG_NO_ACCOUNT);
+            } else {
+                // there is no need for checking for is there more then one
+                // account at this point
+                // since account setup can set only one account at time
+                mAccount = accounts[0];
+                populateDirectoryList();
+            }
+        }
+    }
+
+    private void populateDirectoryList() {
+        setContentView(R.layout.uploader_layout);
+
+        String full_path = "";
+        for (String a : mParents)
+            full_path += a + "/";
+        
+        Log_OC.d(TAG, "Populating view with content of : " + full_path);
+        
+        mFile = mStorageManager.getFileByPath(full_path);
+        if (mFile != null) {
+            Vector<OCFile> files = mStorageManager.getDirectoryContent(mFile);
+            List<HashMap<String, Object>> data = new LinkedList<HashMap<String,Object>>();
+            for (OCFile f : files) {
+                HashMap<String, Object> h = new HashMap<String, Object>();
+                if (f.isDirectory()) {
+                    h.put("dirname", f.getFileName());
+                    data.add(h);
+                }
+            }
+            SimpleAdapter sa = new SimpleAdapter(this,
+                                                data,
+                                                R.layout.uploader_list_item_layout,
+                                                new String[] {"dirname"},
+                                                new int[] {R.id.textView1});
+            setListAdapter(sa);
+            Button btn = (Button) findViewById(R.id.uploader_choose_folder);
+            btn.setOnClickListener(this);
+            getListView().setOnItemClickListener(this);
+        }
+    }
+
+    private boolean prepareStreamsToUpload() {
+        if (getIntent().getAction().equals(Intent.ACTION_SEND)) {
+            mStreamsToUpload = new ArrayList<Parcelable>();
+            mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));
+        } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {
+            mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+        }
+        return (mStreamsToUpload != null && mStreamsToUpload.get(0) != null);
+    }
+
+    public void uploadFiles() {
+        try {
+            WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext());
+
+            // create last directory in path if necessary
+            if (mCreateDir) {
+                wdc.createDirectory(mUploadPath);
+            }
+
+            String[] local = new String[mStreamsToUpload.size()], remote = new String[mStreamsToUpload.size()];
+
+            for (int i = 0; i < mStreamsToUpload.size(); ++i) {
+                Uri uri = (Uri) mStreamsToUpload.get(i);
+                if (uri.getScheme().equals("content")) {
+                    Cursor c = getContentResolver().query((Uri) mStreamsToUpload.get(i),
+                                                      CONTENT_PROJECTION,
+                                                      null,
+                                                      null,
+                                                      null);
+
+                    if (!c.moveToFirst())
+                        continue;
+
+                    final String display_name = c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),
+                                data = c.getString(c.getColumnIndex(Media.DATA));
+                    local[i] = data;
+                    remote[i] = mUploadPath + display_name;
+                } else if (uri.getScheme().equals("file")) {
+                    final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme() + "://", ""));
+                    local[i] = file.getAbsolutePath();
+                    remote[i] = mUploadPath + file.getName();
+                }
+
+            }
+            Intent intent = new Intent(getApplicationContext(), FileUploader.class);
+            intent.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_MULTIPLE_FILES);
+            intent.putExtra(FileUploader.KEY_LOCAL_FILE, local);
+            intent.putExtra(FileUploader.KEY_REMOTE_FILE, remote);
+            intent.putExtra(FileUploader.KEY_ACCOUNT, mAccount);
+            startService(intent);
+            finish();
+            
+        } catch (SecurityException e) {
+            String message = String.format(getString(R.string.uploader_error_forbidden_content), getString(R.string.app_name));
+            Toast.makeText(this, message, Toast.LENGTH_LONG).show();            
+        }
+    }
+
+}
index 9d8b4ab..d0e99f5 100644 (file)
-/* ownCloud Android client application\r
- *   Copyright (C) 2012  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- *   This program is free software: you can redistribute it and/or modify\r
- *   it under the terms of the GNU General Public License as published by\r
- *   the Free Software Foundation, either version 2 of the License, or\r
- *   (at your option) any later version.\r
- *\r
- *   This program is distributed in the hope that it will be useful,\r
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- *   GNU General Public License for more details.\r
- *\r
- *   You should have received a copy of the GNU General Public License\r
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package com.owncloud.android.authenticator;\r
-\r
-import com.owncloud.android.ui.activity.AuthenticatorActivity;\r
-\r
-import android.accounts.*;\r
-import android.content.Context;\r
-import android.content.Intent;\r
-import android.os.Bundle;\r
-import android.util.Log;\r
-\r
-public class AccountAuthenticator extends AbstractAccountAuthenticator {\r
-    /**\r
-     * Is used by android system to assign accounts to authenticators. Should be\r
-     * used by application and all extensions.\r
-     */\r
-    public static final String ACCOUNT_TYPE = "owncloud";\r
-    public static final String AUTH_TOKEN_TYPE = "org.owncloud";\r
-\r
-    public static final String KEY_AUTH_TOKEN_TYPE = "authTokenType";\r
-    public static final String KEY_REQUIRED_FEATURES = "requiredFeatures";\r
-    public static final String KEY_LOGIN_OPTIONS = "loginOptions";\r
-    public static final String KEY_ACCOUNT = "account";\r
-    /**\r
-     * Value under this key should handle path to webdav php script. Will be\r
-     * removed and usage should be replaced by combining\r
-     * {@link com.owncloud.android.authenticator.AuthenticatorActivity.KEY_OC_BASE_URL} and\r
-     * {@link com.owncloud.android.utils.OwnCloudVersion}\r
-     * \r
-     * @deprecated\r
-     */\r
-    public static final String KEY_OC_URL = "oc_url";\r
-    /**\r
-     * Version should be 3 numbers separated by dot so it can be parsed by\r
-     * {@link com.owncloud.android.utils.OwnCloudVersion}\r
-     */\r
-    public static final String KEY_OC_VERSION = "oc_version";\r
-    /**\r
-     * Base url should point to owncloud installation without trailing / ie:\r
-     * http://server/path or https://owncloud.server\r
-     */\r
-    public static final String KEY_OC_BASE_URL = "oc_base_url";\r
-\r
-    private static final String TAG = "AccountAuthenticator";\r
-    private Context mContext;\r
-\r
-    public AccountAuthenticator(Context context) {\r
-        super(context);\r
-        mContext = context;\r
-    }\r
-\r
-    /**\r
-     * {@inheritDoc}\r
-     */\r
-    @Override\r
-    public Bundle addAccount(AccountAuthenticatorResponse response,\r
-            String accountType, String authTokenType,\r
-            String[] requiredFeatures, Bundle options)\r
-            throws NetworkErrorException {\r
-        Log.i(TAG, "Adding account with type " + accountType\r
-                + " and auth token " + authTokenType);\r
-        try {\r
-            validateAccountType(accountType);\r
-        } catch (AuthenticatorException e) {\r
-            Log.e(TAG, "Failed to validate account type " + accountType + ": "\r
-                    + e.getMessage());\r
-            e.printStackTrace();\r
-            return e.getFailureBundle();\r
-        }\r
-        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
-        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
-                response);\r
-        intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
-        intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures);\r
-        intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
-\r
-        setIntentFlags(intent);\r
-        final Bundle bundle = new Bundle();\r
-        bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
-        return bundle;\r
-    }\r
-\r
-    /**\r
-     * {@inheritDoc}\r
-     */\r
-    @Override\r
-    public Bundle confirmCredentials(AccountAuthenticatorResponse response,\r
-            Account account, Bundle options) throws NetworkErrorException {\r
-        try {\r
-            validateAccountType(account.type);\r
-        } catch (AuthenticatorException e) {\r
-            Log.e(TAG, "Failed to validate account type " + account.type + ": "\r
-                    + e.getMessage());\r
-            e.printStackTrace();\r
-            return e.getFailureBundle();\r
-        }\r
-        Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
-        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
-                response);\r
-        intent.putExtra(KEY_ACCOUNT, account);\r
-        intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
-\r
-        setIntentFlags(intent);\r
-\r
-        Bundle resultBundle = new Bundle();\r
-        resultBundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
-        return resultBundle;\r
-    }\r
-\r
-    @Override\r
-    public Bundle editProperties(AccountAuthenticatorResponse response,\r
-            String accountType) {\r
-        return null;\r
-    }\r
-\r
-    @Override\r
-    public Bundle getAuthToken(AccountAuthenticatorResponse response,\r
-            Account account, String authTokenType, Bundle options)\r
-            throws NetworkErrorException {\r
-        try {\r
-            validateAccountType(account.type);\r
-            validateAuthTokenType(authTokenType);\r
-        } catch (AuthenticatorException e) {\r
-            Log.e(TAG, "Failed to validate account type " + account.type + ": "\r
-                    + e.getMessage());\r
-            e.printStackTrace();\r
-            return e.getFailureBundle();\r
-        }\r
-        final AccountManager am = AccountManager.get(mContext);\r
-        final String password = am.getPassword(account);\r
-        if (password != null) {\r
-            final Bundle result = new Bundle();\r
-            result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);\r
-            result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);\r
-            result.putString(AccountManager.KEY_AUTHTOKEN, password);\r
-            return result;\r
-        }\r
-\r
-        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
-        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
-                response);\r
-        intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
-        intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
-        intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name);\r
-\r
-        final Bundle bundle = new Bundle();\r
-        bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
-        return bundle;\r
-    }\r
-\r
-    @Override\r
-    public String getAuthTokenLabel(String authTokenType) {\r
-        return null;\r
-    }\r
-\r
-    @Override\r
-    public Bundle hasFeatures(AccountAuthenticatorResponse response,\r
-            Account account, String[] features) throws NetworkErrorException {\r
-        final Bundle result = new Bundle();\r
-        result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);\r
-        return result;\r
-    }\r
-\r
-    @Override\r
-    public Bundle updateCredentials(AccountAuthenticatorResponse response,\r
-            Account account, String authTokenType, Bundle options)\r
-            throws NetworkErrorException {\r
-        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
-        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
-                response);\r
-        intent.putExtra(KEY_ACCOUNT, account);\r
-        intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);\r
-        intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
-        setIntentFlags(intent);\r
-\r
-        final Bundle bundle = new Bundle();\r
-        bundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
-        return bundle;\r
-    }\r
-\r
-    @Override\r
-    public Bundle getAccountRemovalAllowed(\r
-            AccountAuthenticatorResponse response, Account account)\r
-            throws NetworkErrorException {\r
-        return super.getAccountRemovalAllowed(response, account);\r
-    }\r
-\r
-    private void setIntentFlags(Intent intent) {\r
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\r
-        intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);\r
-        intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);\r
-        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);\r
-        intent.addFlags(Intent.FLAG_FROM_BACKGROUND);\r
-    }\r
-\r
-    private void validateAccountType(String type)\r
-            throws UnsupportedAccountTypeException {\r
-        if (!type.equals(ACCOUNT_TYPE)) {\r
-            throw new UnsupportedAccountTypeException();\r
-        }\r
-    }\r
-\r
-    private void validateAuthTokenType(String authTokenType)\r
-            throws UnsupportedAuthTokenTypeException {\r
-        if (!authTokenType.equals(AUTH_TOKEN_TYPE)) {\r
-            throw new UnsupportedAuthTokenTypeException();\r
-        }\r
-    }\r
-\r
-    public static class AuthenticatorException extends Exception {\r
-        private static final long serialVersionUID = 1L;\r
-        private Bundle mFailureBundle;\r
-\r
-        public AuthenticatorException(int code, String errorMsg) {\r
-            mFailureBundle = new Bundle();\r
-            mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code);\r
-            mFailureBundle\r
-                    .putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);\r
-        }\r
-\r
-        public Bundle getFailureBundle() {\r
-            return mFailureBundle;\r
-        }\r
-    }\r
-\r
-    public static class UnsupportedAccountTypeException extends\r
-            AuthenticatorException {\r
-        private static final long serialVersionUID = 1L;\r
-\r
-        public UnsupportedAccountTypeException() {\r
-            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
-                    "Unsupported account type");\r
-        }\r
-    }\r
-\r
-    public static class UnsupportedAuthTokenTypeException extends\r
-            AuthenticatorException {\r
-        private static final long serialVersionUID = 1L;\r
-\r
-        public UnsupportedAuthTokenTypeException() {\r
-            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
-                    "Unsupported auth token type");\r
-        }\r
-    }\r
-\r
-    public static class UnsupportedFeaturesException extends\r
-            AuthenticatorException {\r
-        public static final long serialVersionUID = 1L;\r
-\r
-        public UnsupportedFeaturesException() {\r
-            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
-                    "Unsupported features");\r
-        }\r
-    }\r
-\r
-    public static class AccessDeniedException extends AuthenticatorException {\r
-        public AccessDeniedException(int code, String errorMsg) {\r
-            super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied");\r
-        }\r
-\r
-        private static final long serialVersionUID = 1L;\r
-\r
-    }\r
-}\r
+/* ownCloud Android client application
+ *   Copyright (C) 2012  Bartek Przybylski
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.authenticator;
+
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.ui.activity.AuthenticatorActivity;
+
+import android.accounts.*;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+public class AccountAuthenticator extends AbstractAccountAuthenticator {
+    /**
+     * Is used by android system to assign accounts to authenticators. Should be
+     * used by application and all extensions.
+     */
+    public static final String ACCOUNT_TYPE = "owncloud";
+    public static final String AUTH_TOKEN_TYPE = "org.owncloud";
+
+    public static final String KEY_AUTH_TOKEN_TYPE = "authTokenType";
+    public static final String KEY_REQUIRED_FEATURES = "requiredFeatures";
+    public static final String KEY_LOGIN_OPTIONS = "loginOptions";
+    public static final String KEY_ACCOUNT = "account";
+    /**
+     * Value under this key should handle path to webdav php script. Will be
+     * removed and usage should be replaced by combining
+     * {@link com.owncloud.android.authenticator.AuthenticatorActivity.KEY_OC_BASE_URL} and
+     * {@link com.owncloud.android.utils.OwnCloudVersion}
+     * 
+     * @deprecated
+     */
+    public static final String KEY_OC_URL = "oc_url";
+    /**
+     * Version should be 3 numbers separated by dot so it can be parsed by
+     * {@link com.owncloud.android.utils.OwnCloudVersion}
+     */
+    public static final String KEY_OC_VERSION = "oc_version";
+    /**
+     * Base url should point to owncloud installation without trailing / ie:
+     * http://server/path or https://owncloud.server
+     */
+    public static final String KEY_OC_BASE_URL = "oc_base_url";
+
+    private static final String TAG = "AccountAuthenticator";
+    private Context mContext;
+
+    public AccountAuthenticator(Context context) {
+        super(context);
+        mContext = context;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Bundle addAccount(AccountAuthenticatorResponse response,
+            String accountType, String authTokenType,
+            String[] requiredFeatures, Bundle options)
+            throws NetworkErrorException {
+        Log_OC.i(TAG, "Adding account with type " + accountType
+                + " and auth token " + authTokenType);
+        try {
+            validateAccountType(accountType);
+        } catch (AuthenticatorException e) {
+            Log_OC.e(TAG, "Failed to validate account type " + accountType + ": "
+                    + e.getMessage());
+            e.printStackTrace();
+            return e.getFailureBundle();
+        }
+        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
+        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
+                response);
+        intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
+        intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures);
+        intent.putExtra(KEY_LOGIN_OPTIONS, options);
+
+        setIntentFlags(intent);
+        final Bundle bundle = new Bundle();
+        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
+        return bundle;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Bundle confirmCredentials(AccountAuthenticatorResponse response,
+            Account account, Bundle options) throws NetworkErrorException {
+        try {
+            validateAccountType(account.type);
+        } catch (AuthenticatorException e) {
+            Log_OC.e(TAG, "Failed to validate account type " + account.type + ": "
+                    + e.getMessage());
+            e.printStackTrace();
+            return e.getFailureBundle();
+        }
+        Intent intent = new Intent(mContext, AuthenticatorActivity.class);
+        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
+                response);
+        intent.putExtra(KEY_ACCOUNT, account);
+        intent.putExtra(KEY_LOGIN_OPTIONS, options);
+
+        setIntentFlags(intent);
+
+        Bundle resultBundle = new Bundle();
+        resultBundle.putParcelable(AccountManager.KEY_INTENT, intent);
+        return resultBundle;
+    }
+
+    @Override
+    public Bundle editProperties(AccountAuthenticatorResponse response,
+            String accountType) {
+        return null;
+    }
+
+    @Override
+    public Bundle getAuthToken(AccountAuthenticatorResponse response,
+            Account account, String authTokenType, Bundle options)
+            throws NetworkErrorException {
+        try {
+            validateAccountType(account.type);
+            validateAuthTokenType(authTokenType);
+        } catch (AuthenticatorException e) {
+            Log_OC.e(TAG, "Failed to validate account type " + account.type + ": "
+                    + e.getMessage());
+            e.printStackTrace();
+            return e.getFailureBundle();
+        }
+        final AccountManager am = AccountManager.get(mContext);
+        final String password = am.getPassword(account);
+        if (password != null) {
+            final Bundle result = new Bundle();
+            result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
+            result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);
+            result.putString(AccountManager.KEY_AUTHTOKEN, password);
+            return result;
+        }
+
+        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
+        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
+                response);
+        intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
+        intent.putExtra(KEY_LOGIN_OPTIONS, options);
+        intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name);
+
+        final Bundle bundle = new Bundle();
+        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
+        return bundle;
+    }
+
+    @Override
+    public String getAuthTokenLabel(String authTokenType) {
+        return null;
+    }
+
+    @Override
+    public Bundle hasFeatures(AccountAuthenticatorResponse response,
+            Account account, String[] features) throws NetworkErrorException {
+        final Bundle result = new Bundle();
+        result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+        return result;
+    }
+
+    @Override
+    public Bundle updateCredentials(AccountAuthenticatorResponse response,
+            Account account, String authTokenType, Bundle options)
+            throws NetworkErrorException {
+        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
+        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
+                response);
+        intent.putExtra(KEY_ACCOUNT, account);
+        intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
+        intent.putExtra(KEY_LOGIN_OPTIONS, options);
+        setIntentFlags(intent);
+
+        final Bundle bundle = new Bundle();
+        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
+        return bundle;
+    }
+
+    @Override
+    public Bundle getAccountRemovalAllowed(
+            AccountAuthenticatorResponse response, Account account)
+            throws NetworkErrorException {
+        return super.getAccountRemovalAllowed(response, account);
+    }
+
+    private void setIntentFlags(Intent intent) {
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        intent.addFlags(Intent.FLAG_FROM_BACKGROUND);
+    }
+
+    private void validateAccountType(String type)
+            throws UnsupportedAccountTypeException {
+        if (!type.equals(ACCOUNT_TYPE)) {
+            throw new UnsupportedAccountTypeException();
+        }
+    }
+
+    private void validateAuthTokenType(String authTokenType)
+            throws UnsupportedAuthTokenTypeException {
+        if (!authTokenType.equals(AUTH_TOKEN_TYPE)) {
+            throw new UnsupportedAuthTokenTypeException();
+        }
+    }
+
+    public static class AuthenticatorException extends Exception {
+        private static final long serialVersionUID = 1L;
+        private Bundle mFailureBundle;
+
+        public AuthenticatorException(int code, String errorMsg) {
+            mFailureBundle = new Bundle();
+            mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code);
+            mFailureBundle
+                    .putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+        }
+
+        public Bundle getFailureBundle() {
+            return mFailureBundle;
+        }
+    }
+
+    public static class UnsupportedAccountTypeException extends
+            AuthenticatorException {
+        private static final long serialVersionUID = 1L;
+
+        public UnsupportedAccountTypeException() {
+            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
+                    "Unsupported account type");
+        }
+    }
+
+    public static class UnsupportedAuthTokenTypeException extends
+            AuthenticatorException {
+        private static final long serialVersionUID = 1L;
+
+        public UnsupportedAuthTokenTypeException() {
+            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
+                    "Unsupported auth token type");
+        }
+    }
+
+    public static class UnsupportedFeaturesException extends
+            AuthenticatorException {
+        public static final long serialVersionUID = 1L;
+
+        public UnsupportedFeaturesException() {
+            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
+                    "Unsupported features");
+        }
+    }
+
+    public static class AccessDeniedException extends AuthenticatorException {
+        public AccessDeniedException(int code, String errorMsg) {
+            super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied");
+        }
+
+        private static final long serialVersionUID = 1L;
+
+    }
+}
index 41aad01..f38302a 100644 (file)
@@ -26,6 +26,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Vector;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.db.ProviderMeta;
 import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
 import com.owncloud.android.utils.FileStorageUtils;
@@ -156,7 +157,7 @@ public class FileDataStorageManager implements DataStorageManager {
                             cv, ProviderTableMeta._ID + "=?",
                             new String[] { String.valueOf(file.getFileId()) });
                 } catch (RemoteException e) {
-                    Log.e(TAG,
+                    Log_OC.e(TAG,
                             "Fail to insert insert file to database "
                                     + e.getMessage());
                 }
@@ -171,7 +172,7 @@ public class FileDataStorageManager implements DataStorageManager {
                     result_uri = getContentProvider().insert(
                             ProviderTableMeta.CONTENT_URI_FILE, cv);
                 } catch (RemoteException e) {
-                    Log.e(TAG,
+                    Log_OC.e(TAG,
                             "Fail to insert insert file to database "
                                     + e.getMessage());
                 }
@@ -256,10 +257,10 @@ public class FileDataStorageManager implements DataStorageManager {
             }
             
         } catch (OperationApplicationException e) {
-            Log.e(TAG, "Fail to update/insert list of files to database " + e.getMessage());
+            Log_OC.e(TAG, "Fail to update/insert list of files to database " + e.getMessage());
             
         } catch (RemoteException e) {
-            Log.e(TAG, "Fail to update/insert list of files to database " + e.getMessage());
+            Log_OC.e(TAG, "Fail to update/insert list of files to database " + e.getMessage());
         }
         
         // update new id in file objects for insertions
@@ -269,7 +270,7 @@ public class FileDataStorageManager implements DataStorageManager {
                 if (results[i].uri != null) {
                     newId = Long.parseLong(results[i].uri.getPathSegments().get(1));
                     files.get(i).setFileId(newId);
-                    //Log.v(TAG, "Found and added id in insertion for " + files.get(i).getRemotePath());
+                    //Log_OC.v(TAG, "Found and added id in insertion for " + files.get(i).getRemotePath());
                 }
             }
         }
@@ -321,7 +322,7 @@ public class FileDataStorageManager implements DataStorageManager {
                             ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
                             new String[] { mAccount.name }, null);
                 } catch (RemoteException e) {
-                    Log.e(TAG, e.getMessage());
+                    Log_OC.e(TAG, e.getMessage());
                     return ret;
                 }
             } else {
@@ -364,7 +365,7 @@ public class FileDataStorageManager implements DataStorageManager {
                                 + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
                         new String[] { value, mAccount.name }, null);
             } catch (RemoteException e) {
-                Log.e(TAG,
+                Log_OC.e(TAG,
                         "Couldn't determine file existance, assuming non existance: "
                                 + e.getMessage());
                 return false;
@@ -394,7 +395,7 @@ public class FileDataStorageManager implements DataStorageManager {
                                 + "=?", new String[] { value, mAccount.name },
                         null);
             } catch (RemoteException e) {
-                Log.e(TAG, "Could not get file details: " + e.getMessage());
+                Log_OC.e(TAG, "Could not get file details: " + e.getMessage());
                 c = null;
             }
         }
@@ -517,7 +518,7 @@ public class FileDataStorageManager implements DataStorageManager {
                                                     ProviderTableMeta.FILE_ACCOUNT_OWNER + "=? AND " + ProviderTableMeta.FILE_PATH + " LIKE ?",
                                                     new String[] { mAccount.name, dir.getRemotePath() + "%" }, null);
                 } catch (RemoteException e) {
-                    Log.e(TAG, e.getMessage());
+                    Log_OC.e(TAG, e.getMessage());
                 }
             } else {
                 c = getContentResolver().query(ProviderTableMeta.CONTENT_URI, 
@@ -558,10 +559,10 @@ public class FileDataStorageManager implements DataStorageManager {
                 }
                 
             } catch (OperationApplicationException e) {
-                Log.e(TAG, "Fail to update descendants of " + dir.getFileId() + " in database", e);
+                Log_OC.e(TAG, "Fail to update descendants of " + dir.getFileId() + " in database", e);
                 
             } catch (RemoteException e) {
-                Log.e(TAG, "Fail to update desendants of " + dir.getFileId() + " in database", e);
+                Log_OC.e(TAG, "Fail to update desendants of " + dir.getFileId() + " in database", e);
             }
             
         }
index 8b07996..da105d9 100644 (file)
@@ -21,11 +21,10 @@ package com.owncloud.android.datamodel;
 
 import java.io.File;
 
-import android.content.Intent;
-import android.net.Uri;
+import com.owncloud.android.Log_OC;
+
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Log;
 import android.webkit.MimeTypeMap;
 
 public class OCFile implements Parcelable, Comparable<OCFile> {
@@ -265,7 +264,7 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
      * Does nothing if the new name is null, empty or includes "/" ; or if the file is the root directory 
      */
     public void setFileName(String name) {
-        Log.d(TAG, "OCFile name changin from " + mRemotePath);
+        Log_OC.d(TAG, "OCFile name changin from " + mRemotePath);
         if (name != null && name.length() > 0 && !name.contains(PATH_SEPARATOR) && !mRemotePath.equals(PATH_SEPARATOR)) {
             String parent = (new File(getRemotePath())).getParent();
             parent = (parent.endsWith(PATH_SEPARATOR)) ? parent : parent + PATH_SEPARATOR;
@@ -273,7 +272,7 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
             if (isDirectory()) {
                 mRemotePath += PATH_SEPARATOR;
             }
-            Log.d(TAG, "OCFile name changed to " + mRemotePath);
+            Log_OC.d(TAG, "OCFile name changed to " + mRemotePath);
         }
     }
 
index 4d212fe..788fec9 100644 (file)
@@ -17,6 +17,8 @@
  */
 package com.owncloud.android.db;
 
+import com.owncloud.android.Log_OC;
+
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
@@ -57,7 +59,7 @@ public class DbHandler {
         cv.put("attempt", UPLOAD_STATUS_UPLOAD_LATER);
         cv.put("message", message);
         long result = mDB.insert(TABLE_INSTANT_UPLOAD, null, cv);
-        Log.d(TABLE_INSTANT_UPLOAD, "putFileForLater returns with: " + result + " for file: " + filepath);
+        Log_OC.d(TABLE_INSTANT_UPLOAD, "putFileForLater returns with: " + result + " for file: " + filepath);
         return result != -1;
     }
 
@@ -66,7 +68,7 @@ public class DbHandler {
         cv.put("attempt", status);
         cv.put("message", message);
         int result = mDB.update(TABLE_INSTANT_UPLOAD, cv, "path=?", new String[] { filepath });
-        Log.d(TABLE_INSTANT_UPLOAD, "updateFileState returns with: " + result + " for file: " + filepath);
+        Log_OC.d(TABLE_INSTANT_UPLOAD, "updateFileState returns with: " + result + " for file: " + filepath);
         return result;
     }
 
@@ -89,7 +91,7 @@ public class DbHandler {
      */
     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);
+        Log_OC.d(TABLE_INSTANT_UPLOAD, "delete returns with: " + result + " for file: " + localPath);
         return result != 0;
 
     }
index ccef340..6b800fd 100644 (file)
@@ -19,6 +19,7 @@
 
 package com.owncloud.android.extensions;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 import android.content.Intent;
 import android.os.Bundle;
@@ -62,7 +63,7 @@ public class ExtensionsAvailableDialog extends DialogFragment implements
             getActivity().finish();
             break;
         default:
-            Log.e("EAD", "Button with unknown id clicked " + v.getId());
+            Log_OC.e("EAD", "Button with unknown id clicked " + v.getId());
         }
     }
 
index 5b16729..0452109 100644 (file)
@@ -28,6 +28,7 @@ import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.utils.OwnCloudVersion;
 
 
@@ -81,7 +82,7 @@ public class ExtensionsListActivity extends ListActivity {
             final JSONArray ar;
             try {
                 hc.executeMethod(gm);
-                Log.e("ASD", gm.getResponseBodyAsString() + "");
+                Log_OC.e("ASD", gm.getResponseBodyAsString() + "");
                 ar = new JSONObject(gm.getResponseBodyAsString())
                         .getJSONArray("apps");
             } catch (Exception e) {
index e322fa5..43ef367 100644 (file)
@@ -19,6 +19,7 @@
 
 package com.owncloud.android.files;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.files.services.FileObserverService;
 
 import android.content.BroadcastReceiver;
@@ -33,15 +34,15 @@ public class BootupBroadcastReceiver extends BroadcastReceiver {
     @Override
     public void onReceive(Context context, Intent intent) {
         if (!intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
-            Log.wtf(TAG, "Incorrect action sent " + intent.getAction());
+            Log_OC.wtf(TAG, "Incorrect action sent " + intent.getAction());
             return;
         }
-        Log.d(TAG, "Starting file observer service...");
+        Log_OC.d(TAG, "Starting file observer service...");
         Intent i = new Intent(context, FileObserverService.class);
         i.putExtra(FileObserverService.KEY_FILE_CMD,
                    FileObserverService.CMD_INIT_OBSERVED_LIST);
         context.startService(i);
-        Log.d(TAG, "DONE");
+        Log_OC.d(TAG, "DONE");
     }
 
 }
index 1232fa1..c946ec9 100644 (file)
@@ -35,6 +35,7 @@ import android.util.Log;
 import android.webkit.MimeTypeMap;
 
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.authenticator.AccountAuthenticator;
 import com.owncloud.android.db.DbHandler;
 import com.owncloud.android.files.services.FileUploader;
@@ -48,7 +49,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
 
     @Override
     public void onReceive(Context context, Intent intent) {
-        Log.d(TAG, "Received: " + intent.getAction());
+        Log_OC.d(TAG, "Received: " + intent.getAction());
         if (intent.getAction().equals(android.net.ConnectivityManager.CONNECTIVITY_ACTION)) {
             handleConnectivityAction(context, intent);
         } else if (intent.getAction().equals(NEW_PHOTO_ACTION)) {
@@ -56,7 +57,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
         } else if (intent.getAction().equals(FileUploader.UPLOAD_FINISH_MESSAGE)) {
             handleUploadFinished(context, intent);
         } else {
-            Log.e(TAG, "Incorrect intent sent: " + intent.getAction());
+            Log_OC.e(TAG, "Incorrect intent sent: " + intent.getAction());
         }
     }
 
@@ -66,7 +67,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
             DbHandler db = new DbHandler(context);
             String localPath = intent.getStringExtra(FileUploader.EXTRA_OLD_FILE_PATH);
             if (!db.removeIUPendingFile(localPath)) {
-                Log.w(TAG, "Tried to remove non existing instant upload file " + localPath);
+                Log_OC.w(TAG, "Tried to remove non existing instant upload file " + localPath);
             }
             db.close();
         }
@@ -74,20 +75,20 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
 
     private void handleNewPhotoAction(Context context, Intent intent) {
         if (!instantUploadEnabled(context)) {
-            Log.d(TAG, "Instant upload disabled, abording uploading");
+            Log_OC.d(TAG, "Instant upload disabled, abording uploading");
             return;
         }
 
         Account account = AccountUtils.getCurrentOwnCloudAccount(context);
         if (account == null) {
-            Log.w(TAG, "No owncloud account found for instant upload, aborting");
+            Log_OC.w(TAG, "No owncloud account found for instant upload, aborting");
             return;
         }
 
         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());
+            Log_OC.e(TAG, "Couldn't resolve given uri: " + intent.getDataString());
             return;
         }
 
@@ -96,7 +97,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
         String mime_type = c.getString(c.getColumnIndex(Media.MIME_TYPE));
 
         c.close();
-        Log.e(TAG, file_path + "");
+        Log_OC.e(TAG, file_path + "");
 
         // same always temporally the picture to upload
         DbHandler db = new DbHandler(context);
@@ -131,7 +132,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
 
     private void handleConnectivityAction(Context context, Intent intent) {
         if (!instantUploadEnabled(context)) {
-            Log.d(TAG, "Instant upload disabled, abording uploading");
+            Log_OC.d(TAG, "Instant upload disabled, abording uploading");
             return;
         }
 
@@ -156,7 +157,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
                                     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());
+                            Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + f.getName());
                         }
                         if (mimeType == null)
                             mimeType = "application/octet-stream";
@@ -170,7 +171,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
                         context.startService(i);
 
                     } else {
-                        Log.w(TAG, "Instant upload file " + f.getAbsolutePath() + " dont exist anymore");
+                        Log_OC.w(TAG, "Instant upload file " + f.getAbsolutePath() + " dont exist anymore");
                     }
                 } while (c.moveToNext());
             }
index 8e1f736..4f46eba 100644 (file)
@@ -21,6 +21,7 @@ package com.owncloud.android.files;
 
 import java.io.File;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.network.OwnCloudClientUtils;
@@ -71,9 +72,9 @@ public class OwnCloudFileObserver extends FileObserver {
     
     @Override
     public void onEvent(int event, String path) {
-        Log.d(TAG, "Got file modified with event " + event + " and path " + mPath + ((path != null) ? File.separator + path : ""));
+        Log_OC.d(TAG, "Got file modified with event " + event + " and path " + mPath + ((path != null) ? File.separator + path : ""));
         if ((event & mMask) == 0) {
-            Log.wtf(TAG, "Incorrect event " + event + " sent for file " + mPath + ((path != null) ? File.separator + path : "") +
+            Log_OC.wtf(TAG, "Incorrect event " + event + " sent for file " + mPath + ((path != null) ? File.separator + path : "") +
                          " with registered for " + mMask + " and original path " +
                          mPath);
             return;
index aa5583d..39b3e95 100644 (file)
-/* ownCloud Android client application\r
- *   Copyright (C) 2012 Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- *   This program is free software: you can redistribute it and/or modify\r
- *   it under the terms of the GNU General Public License as published by\r
- *   the Free Software Foundation, either version 2 of the License, or\r
- *   (at your option) any later version.\r
- *\r
- *   This program is distributed in the hope that it will be useful,\r
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- *   GNU General Public License for more details.\r
- *\r
- *   You should have received a copy of the GNU General Public License\r
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package com.owncloud.android.files.services;\r
-\r
-import java.io.File;\r
-import java.util.AbstractList;\r
-import java.util.HashMap;\r
-import java.util.Iterator;\r
-import java.util.Map;\r
-import java.util.Vector;\r
-import java.util.concurrent.ConcurrentHashMap;\r
-import java.util.concurrent.ConcurrentMap;\r
-\r
-import com.owncloud.android.datamodel.FileDataStorageManager;\r
-import com.owncloud.android.datamodel.OCFile;\r
-import eu.alefzero.webdav.OnDatatransferProgressListener;\r
-\r
-import com.owncloud.android.network.OwnCloudClientUtils;\r
-import com.owncloud.android.operations.DownloadFileOperation;\r
-import com.owncloud.android.operations.RemoteOperationResult;\r
-import com.owncloud.android.ui.activity.FileDetailActivity;\r
-import com.owncloud.android.ui.fragment.FileDetailFragment;\r
-import com.owncloud.android.ui.preview.PreviewImageActivity;\r
-import com.owncloud.android.ui.preview.PreviewImageFragment;\r
-\r
-import android.accounts.Account;\r
-import android.app.Notification;\r
-import android.app.NotificationManager;\r
-import android.app.PendingIntent;\r
-import android.app.Service;\r
-import android.content.Intent;\r
-import android.os.Binder;\r
-import android.os.Handler;\r
-import android.os.HandlerThread;\r
-import android.os.IBinder;\r
-import android.os.Looper;\r
-import android.os.Message;\r
-import android.os.Process;\r
-import android.util.Log;\r
-import android.widget.RemoteViews;\r
-\r
-import com.owncloud.android.AccountUtils;\r
-import com.owncloud.android.R;\r
-import eu.alefzero.webdav.WebdavClient;\r
-\r
-public class FileDownloader extends Service implements OnDatatransferProgressListener {\r
-    \r
-    public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
-    public static final String EXTRA_FILE = "FILE";\r
-    \r
-    public static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED";\r
-    public static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH";\r
-    public static final String EXTRA_DOWNLOAD_RESULT = "RESULT";    \r
-    public static final String EXTRA_FILE_PATH = "FILE_PATH";\r
-    public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";\r
-    public static final String ACCOUNT_NAME = "ACCOUNT_NAME";\r
-    \r
-    private static final String TAG = "FileDownloader";\r
-\r
-    private Looper mServiceLooper;\r
-    private ServiceHandler mServiceHandler;\r
-    private IBinder mBinder;\r
-    private WebdavClient mDownloadClient = null;\r
-    private Account mLastAccount = null;\r
-    private FileDataStorageManager mStorageManager;\r
-    \r
-    private ConcurrentMap<String, DownloadFileOperation> mPendingDownloads = new ConcurrentHashMap<String, DownloadFileOperation>();\r
-    private DownloadFileOperation mCurrentDownload = null;\r
-    \r
-    private NotificationManager mNotificationManager;\r
-    private Notification mNotification;\r
-    private int mLastPercent;\r
-    \r
-    \r
-    /**\r
-     * Builds a key for mPendingDownloads from the account and file to download\r
-     * \r
-     * @param account   Account where the file to download is stored\r
-     * @param file      File to download\r
-     */\r
-    private String buildRemoteName(Account account, OCFile file) {\r
-        return account.name + file.getRemotePath();\r
-    }\r
-\r
-    \r
-    /**\r
-     * Service initialization\r
-     */\r
-    @Override\r
-    public void onCreate() {\r
-        super.onCreate();\r
-        mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);\r
-        HandlerThread thread = new HandlerThread("FileDownloaderThread",\r
-                Process.THREAD_PRIORITY_BACKGROUND);\r
-        thread.start();\r
-        mServiceLooper = thread.getLooper();\r
-        mServiceHandler = new ServiceHandler(mServiceLooper, this);\r
-        mBinder = new FileDownloaderBinder();\r
-    }\r
-\r
-    \r
-    /**\r
-     * Entry point to add one or several files to the queue of downloads.\r
-     * \r
-     * New downloads are added calling to startService(), resulting in a call to this method. This ensures the service will keep on working \r
-     * although the caller activity goes away.\r
-     */\r
-    @Override\r
-    public int onStartCommand(Intent intent, int flags, int startId) {\r
-        if (    !intent.hasExtra(EXTRA_ACCOUNT) ||\r
-                !intent.hasExtra(EXTRA_FILE)\r
-                /*!intent.hasExtra(EXTRA_FILE_PATH) ||\r
-                !intent.hasExtra(EXTRA_REMOTE_PATH)*/\r
-           ) {\r
-            Log.e(TAG, "Not enough information provided in intent");\r
-            return START_NOT_STICKY;\r
-        }\r
-        Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);\r
-        OCFile file = intent.getParcelableExtra(EXTRA_FILE);\r
-        \r
-        AbstractList<String> requestedDownloads = new Vector<String>(); // dvelasco: now this always contains just one element, but that can change in a near future (download of multiple selection)\r
-        String downloadKey = buildRemoteName(account, file);\r
-        try {\r
-            DownloadFileOperation newDownload = new DownloadFileOperation(account, file); \r
-            mPendingDownloads.putIfAbsent(downloadKey, newDownload);\r
-            newDownload.addDatatransferProgressListener(this);\r
-            newDownload.addDatatransferProgressListener((FileDownloaderBinder)mBinder);\r
-            requestedDownloads.add(downloadKey);\r
-            sendBroadcastNewDownload(newDownload);\r
-            \r
-        } catch (IllegalArgumentException e) {\r
-            Log.e(TAG, "Not enough information provided in intent: " + e.getMessage());\r
-            return START_NOT_STICKY;\r
-        }\r
-        \r
-        if (requestedDownloads.size() > 0) {\r
-            Message msg = mServiceHandler.obtainMessage();\r
-            msg.arg1 = startId;\r
-            msg.obj = requestedDownloads;\r
-            mServiceHandler.sendMessage(msg);\r
-        }\r
-\r
-        return START_NOT_STICKY;\r
-    }\r
-    \r
-    \r
-    /**\r
-     * Provides a binder object that clients can use to perform operations on the queue of downloads, excepting the addition of new files. \r
-     * \r
-     * Implemented to perform cancellation, pause and resume of existing downloads.\r
-     */\r
-    @Override\r
-    public IBinder onBind(Intent arg0) {\r
-        return mBinder;\r
-    }\r
-\r
-\r
-    /**\r
-     * Called when ALL the bound clients were onbound.\r
-     */\r
-    @Override\r
-    public boolean onUnbind(Intent intent) {\r
-        ((FileDownloaderBinder)mBinder).clearListeners();\r
-        return false;   // not accepting rebinding (default behaviour)\r
-    }\r
-\r
-    \r
-    /**\r
-     *  Binder to let client components to perform operations on the queue of downloads.\r
-     * \r
-     *  It provides by itself the available operations.\r
-     */\r
-    public class FileDownloaderBinder extends Binder implements OnDatatransferProgressListener {\r
-        \r
-        /** \r
-         * Map of listeners that will be reported about progress of downloads from a {@link FileDownloaderBinder} instance \r
-         */\r
-        private Map<String, OnDatatransferProgressListener> mBoundListeners = new HashMap<String, OnDatatransferProgressListener>();\r
-        \r
-        \r
-        /**\r
-         * Cancels a pending or current download of a remote file.\r
-         * \r
-         * @param account       Owncloud account where the remote file is stored.\r
-         * @param file          A file in the queue of pending downloads\r
-         */\r
-        public void cancel(Account account, OCFile file) {\r
-            DownloadFileOperation download = null;\r
-            synchronized (mPendingDownloads) {\r
-                download = mPendingDownloads.remove(buildRemoteName(account, file));\r
-            }\r
-            if (download != null) {\r
-                download.cancel();\r
-            }\r
-        }\r
-        \r
-        \r
-        public void clearListeners() {\r
-            mBoundListeners.clear();\r
-        }\r
-\r
-\r
-        /**\r
-         * Returns True when the file described by 'file' in the ownCloud account 'account' is downloading or waiting to download.\r
-         * \r
-         * If 'file' is a directory, returns 'true' if some of its descendant files is downloading or waiting to download. \r
-         * \r
-         * @param account       Owncloud account where the remote file is stored.\r
-         * @param file          A file that could be in the queue of downloads.\r
-         */\r
-        public boolean isDownloading(Account account, OCFile file) {\r
-            if (account == null || file == null) return false;\r
-            String targetKey = buildRemoteName(account, file);\r
-            synchronized (mPendingDownloads) {\r
-                if (file.isDirectory()) {\r
-                    // this can be slow if there are many downloads :(\r
-                    Iterator<String> it = mPendingDownloads.keySet().iterator();\r
-                    boolean found = false;\r
-                    while (it.hasNext() && !found) {\r
-                        found = it.next().startsWith(targetKey);\r
-                    }\r
-                    return found;\r
-                } else {\r
-                    return (mPendingDownloads.containsKey(targetKey));\r
-                }\r
-            }\r
-        }\r
-\r
-        \r
-        /**\r
-         * Adds a listener interested in the progress of the download for a concrete file.\r
-         * \r
-         * @param listener      Object to notify about progress of transfer.    \r
-         * @param account       ownCloud account holding the file of interest.\r
-         * @param file          {@link OCfile} of interest for listener. \r
-         */\r
-        public void addDatatransferProgressListener (OnDatatransferProgressListener listener, Account account, OCFile file) {\r
-            if (account == null || file == null || listener == null) return;\r
-            String targetKey = buildRemoteName(account, file);\r
-            mBoundListeners.put(targetKey, listener);\r
-        }\r
-        \r
-        \r
-        \r
-        /**\r
-         * Removes a listener interested in the progress of the download for a concrete file.\r
-         * \r
-         * @param listener      Object to notify about progress of transfer.    \r
-         * @param account       ownCloud account holding the file of interest.\r
-         * @param file          {@link OCfile} of interest for listener. \r
-         */\r
-        public void removeDatatransferProgressListener (OnDatatransferProgressListener listener, Account account, OCFile file) {\r
-            if (account == null || file == null || listener == null) return;\r
-            String targetKey = buildRemoteName(account, file);\r
-            if (mBoundListeners.get(targetKey) == listener) {\r
-                mBoundListeners.remove(targetKey);\r
-            }\r
-        }\r
-\r
-\r
-        @Override\r
-        public void onTransferProgress(long progressRate) {\r
-            // old way, should not be in use any more\r
-        }\r
-\r
-\r
-        @Override\r
-        public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer,\r
-                String fileName) {\r
-            String key = buildRemoteName(mCurrentDownload.getAccount(), mCurrentDownload.getFile());\r
-            OnDatatransferProgressListener boundListener = mBoundListeners.get(key);\r
-            if (boundListener != null) {\r
-                boundListener.onTransferProgress(progressRate, totalTransferredSoFar, totalToTransfer, fileName);\r
-            }\r
-        }\r
-        \r
-    }\r
-    \r
-    \r
-    /** \r
-     * Download worker. Performs the pending downloads in the order they were requested. \r
-     * \r
-     * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}. \r
-     */\r
-    private static class ServiceHandler extends Handler {\r
-        // don't make it a final class, and don't remove the static ; lint will warn about a possible memory leak\r
-        FileDownloader mService;\r
-        public ServiceHandler(Looper looper, FileDownloader service) {\r
-            super(looper);\r
-            if (service == null)\r
-                throw new IllegalArgumentException("Received invalid NULL in parameter 'service'");\r
-            mService = service;\r
-        }\r
-\r
-        @Override\r
-        public void handleMessage(Message msg) {\r
-            @SuppressWarnings("unchecked")\r
-            AbstractList<String> requestedDownloads = (AbstractList<String>) msg.obj;\r
-            if (msg.obj != null) {\r
-                Iterator<String> it = requestedDownloads.iterator();\r
-                while (it.hasNext()) {\r
-                    mService.downloadFile(it.next());\r
-                }\r
-            }\r
-            mService.stopSelf(msg.arg1);\r
-        }\r
-    }\r
-    \r
-    \r
-\r
-    /**\r
-     * Core download method: requests a file to download and stores it.\r
-     * \r
-     * @param downloadKey   Key to access the download to perform, contained in mPendingDownloads \r
-     */\r
-    private void downloadFile(String downloadKey) {\r
-        \r
-        synchronized(mPendingDownloads) {\r
-            mCurrentDownload = mPendingDownloads.get(downloadKey);\r
-        }\r
-        \r
-        if (mCurrentDownload != null) {\r
-            \r
-            notifyDownloadStart(mCurrentDownload);\r
-\r
-            /// prepare client object to send the request to the ownCloud server\r
-            if (mDownloadClient == null || !mLastAccount.equals(mCurrentDownload.getAccount())) {\r
-                mLastAccount = mCurrentDownload.getAccount();\r
-                mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());\r
-                mDownloadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());\r
-            }\r
-\r
-            /// perform the download\r
-            RemoteOperationResult downloadResult = null;\r
-            try {\r
-                downloadResult = mCurrentDownload.execute(mDownloadClient);\r
-                if (downloadResult.isSuccess()) {\r
-                    saveDownloadedFile();\r
-                }\r
-            \r
-            } finally {\r
-                synchronized(mPendingDownloads) {\r
-                    mPendingDownloads.remove(downloadKey);\r
-                }\r
-            }\r
-\r
-            \r
-            /// notify result\r
-            notifyDownloadResult(mCurrentDownload, downloadResult);\r
-            \r
-            sendBroadcastDownloadFinished(mCurrentDownload, downloadResult);\r
-        }\r
-    }\r
-\r
-\r
-    /**\r
-     * Updates the OC File after a successful download.\r
-     */\r
-    private void saveDownloadedFile() {\r
-        OCFile file = mCurrentDownload.getFile();\r
-        long syncDate = System.currentTimeMillis();\r
-        file.setLastSyncDateForProperties(syncDate);\r
-        file.setLastSyncDateForData(syncDate);\r
-        file.setModificationTimestamp(mCurrentDownload.getModificationTimestamp());\r
-        file.setModificationTimestampAtLastSyncForData(mCurrentDownload.getModificationTimestamp());\r
-        // file.setEtag(mCurrentDownload.getEtag());    // TODO Etag, where available\r
-        file.setMimetype(mCurrentDownload.getMimeType());\r
-        file.setStoragePath(mCurrentDownload.getSavePath());\r
-        file.setFileLength((new File(mCurrentDownload.getSavePath()).length()));\r
-        mStorageManager.saveFile(file);\r
-    }\r
-\r
-\r
-    /**\r
-     * Creates a status notification to show the download progress\r
-     * \r
-     * @param download  Download operation starting.\r
-     */\r
-    private void notifyDownloadStart(DownloadFileOperation download) {\r
-        /// create status notification with a progress bar\r
-        mLastPercent = 0;\r
-        mNotification = new Notification(R.drawable.icon, getString(R.string.downloader_download_in_progress_ticker), System.currentTimeMillis());\r
-        mNotification.flags |= Notification.FLAG_ONGOING_EVENT;\r
-        mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbar_layout);\r
-        mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, download.getSize() < 0);\r
-        mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.downloader_download_in_progress_content), 0, new File(download.getSavePath()).getName()));\r
-        mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon);\r
-        \r
-        /// includes a pending intent in the notification showing the details view of the file\r
-        Intent showDetailsIntent = null;\r
-        if (PreviewImageFragment.canBePreviewed(download.getFile())) {\r
-            showDetailsIntent = new Intent(this, PreviewImageActivity.class);\r
-        } else {\r
-            showDetailsIntent = new Intent(this, FileDetailActivity.class);\r
-        }\r
-        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, download.getFile());\r
-        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, download.getAccount());\r
-        showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
-        mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0);\r
-        \r
-        mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification);\r
-    }\r
-\r
-    \r
-    /**\r
-     * Callback method to update the progress bar in the status notification.\r
-     */\r
-    @Override\r
-    public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileName) {\r
-        int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));\r
-        if (percent != mLastPercent) {\r
-          mNotification.contentView.setProgressBar(R.id.status_progress, 100, percent, totalToTransfer < 0);\r
-          String text = String.format(getString(R.string.downloader_download_in_progress_content), percent, fileName);\r
-          mNotification.contentView.setTextViewText(R.id.status_text, text);\r
-          mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification);\r
-        }\r
-        mLastPercent = percent;\r
-    }\r
-    \r
-    \r
-    /**\r
-     * Callback method to update the progress bar in the status notification (old version)\r
-     */\r
-    @Override\r
-    public void onTransferProgress(long progressRate) {\r
-        // NOTHING TO DO HERE ANYMORE\r
-    }\r
-    \r
-\r
-    /**\r
-     * Updates the status notification with the result of a download operation.\r
-     * \r
-     * @param downloadResult    Result of the download operation.\r
-     * @param download          Finished download operation\r
-     */\r
-    private void notifyDownloadResult(DownloadFileOperation download, RemoteOperationResult downloadResult) {\r
-        mNotificationManager.cancel(R.string.downloader_download_in_progress_ticker);\r
-        if (!downloadResult.isCancelled()) {\r
-            int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker : R.string.downloader_download_failed_ticker;\r
-            int contentId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_content : R.string.downloader_download_failed_content;\r
-            Notification finalNotification = new Notification(R.drawable.icon, getString(tickerId), System.currentTimeMillis());\r
-            finalNotification.flags |= Notification.FLAG_AUTO_CANCEL;\r
-            Intent showDetailsIntent = null;\r
-            if (downloadResult.isSuccess()) {\r
-                if (PreviewImageFragment.canBePreviewed(download.getFile())) {\r
-                    showDetailsIntent = new Intent(this, PreviewImageActivity.class);\r
-                } else {\r
-                    showDetailsIntent = new Intent(this, FileDetailActivity.class);\r
-                }\r
-                showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, download.getFile());\r
-                showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, download.getAccount());\r
-                showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
-                \r
-            } else {\r
-                // TODO put something smart in showDetailsIntent\r
-                showDetailsIntent = new Intent();\r
-            }\r
-            finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0);\r
-            finalNotification.setLatestEventInfo(getApplicationContext(), getString(tickerId), String.format(getString(contentId), new File(download.getSavePath()).getName()), finalNotification.contentIntent);\r
-            mNotificationManager.notify(tickerId, finalNotification);\r
-        }\r
-    }\r
-    \r
-    \r
-    /**\r
-     * Sends a broadcast when a download finishes in order to the interested activities can update their view\r
-     * \r
-     * @param download          Finished download operation\r
-     * @param downloadResult    Result of the download operation\r
-     */\r
-    private void sendBroadcastDownloadFinished(DownloadFileOperation download, RemoteOperationResult downloadResult) {\r
-        Intent end = new Intent(DOWNLOAD_FINISH_MESSAGE);\r
-        end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess());\r
-        end.putExtra(ACCOUNT_NAME, download.getAccount().name);\r
-        end.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());\r
-        end.putExtra(EXTRA_FILE_PATH, download.getSavePath());\r
-        sendStickyBroadcast(end);\r
-    }\r
-    \r
-    \r
-    /**\r
-     * Sends a broadcast when a new download is added to the queue.\r
-     * \r
-     * @param download          Added download operation\r
-     */\r
-    private void sendBroadcastNewDownload(DownloadFileOperation download) {\r
-        Intent added = new Intent(DOWNLOAD_ADDED_MESSAGE);\r
-        added.putExtra(ACCOUNT_NAME, download.getAccount().name);\r
-        added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());\r
-        added.putExtra(EXTRA_FILE_PATH, download.getSavePath());\r
-        sendStickyBroadcast(added);\r
-    }\r
-\r
-}\r
+/* ownCloud Android client application
+ *   Copyright (C) 2012 Bartek Przybylski
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License 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.files.services;
+
+import java.io.File;
+import java.util.AbstractList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import eu.alefzero.webdav.OnDatatransferProgressListener;
+
+import com.owncloud.android.network.OwnCloudClientUtils;
+import com.owncloud.android.operations.DownloadFileOperation;
+import com.owncloud.android.operations.RemoteOperationResult;
+import com.owncloud.android.ui.activity.FileDetailActivity;
+import com.owncloud.android.ui.fragment.FileDetailFragment;
+import com.owncloud.android.ui.preview.PreviewImageActivity;
+import com.owncloud.android.ui.preview.PreviewImageFragment;
+
+import android.accounts.Account;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.widget.RemoteViews;
+
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.R;
+import eu.alefzero.webdav.WebdavClient;
+
+public class FileDownloader extends Service implements OnDatatransferProgressListener {
+    
+    public static final String EXTRA_ACCOUNT = "ACCOUNT";
+    public static final String EXTRA_FILE = "FILE";
+    
+    public static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED";
+    public static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH";
+    public static final String EXTRA_DOWNLOAD_RESULT = "RESULT";    
+    public static final String EXTRA_FILE_PATH = "FILE_PATH";
+    public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";
+    public static final String ACCOUNT_NAME = "ACCOUNT_NAME";
+    
+    private static final String TAG = "FileDownloader";
+
+    private Looper mServiceLooper;
+    private ServiceHandler mServiceHandler;
+    private IBinder mBinder;
+    private WebdavClient mDownloadClient = null;
+    private Account mLastAccount = null;
+    private FileDataStorageManager mStorageManager;
+    
+    private ConcurrentMap<String, DownloadFileOperation> mPendingDownloads = new ConcurrentHashMap<String, DownloadFileOperation>();
+    private DownloadFileOperation mCurrentDownload = null;
+    
+    private NotificationManager mNotificationManager;
+    private Notification mNotification;
+    private int mLastPercent;
+    
+    
+    /**
+     * Builds a key for mPendingDownloads from the account and file to download
+     * 
+     * @param account   Account where the file to download is stored
+     * @param file      File to download
+     */
+    private String buildRemoteName(Account account, OCFile file) {
+        return account.name + file.getRemotePath();
+    }
+
+    
+    /**
+     * Service initialization
+     */
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+        HandlerThread thread = new HandlerThread("FileDownloaderThread",
+                Process.THREAD_PRIORITY_BACKGROUND);
+        thread.start();
+        mServiceLooper = thread.getLooper();
+        mServiceHandler = new ServiceHandler(mServiceLooper, this);
+        mBinder = new FileDownloaderBinder();
+    }
+
+    
+    /**
+     * Entry point to add one or several files to the queue of downloads.
+     * 
+     * New downloads are added calling to startService(), resulting in a call to this method. This ensures the service will keep on working 
+     * although the caller activity goes away.
+     */
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        if (    !intent.hasExtra(EXTRA_ACCOUNT) ||
+                !intent.hasExtra(EXTRA_FILE)
+                /*!intent.hasExtra(EXTRA_FILE_PATH) ||
+                !intent.hasExtra(EXTRA_REMOTE_PATH)*/
+           ) {
+            Log_OC.e(TAG, "Not enough information provided in intent");
+            return START_NOT_STICKY;
+        }
+        Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);
+        OCFile file = intent.getParcelableExtra(EXTRA_FILE);
+        
+        AbstractList<String> requestedDownloads = new Vector<String>(); // dvelasco: now this always contains just one element, but that can change in a near future (download of multiple selection)
+        String downloadKey = buildRemoteName(account, file);
+        try {
+            DownloadFileOperation newDownload = new DownloadFileOperation(account, file); 
+            mPendingDownloads.putIfAbsent(downloadKey, newDownload);
+            newDownload.addDatatransferProgressListener(this);
+            newDownload.addDatatransferProgressListener((FileDownloaderBinder)mBinder);
+            requestedDownloads.add(downloadKey);
+            sendBroadcastNewDownload(newDownload);
+            
+        } catch (IllegalArgumentException e) {
+            Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage());
+            return START_NOT_STICKY;
+        }
+        
+        if (requestedDownloads.size() > 0) {
+            Message msg = mServiceHandler.obtainMessage();
+            msg.arg1 = startId;
+            msg.obj = requestedDownloads;
+            mServiceHandler.sendMessage(msg);
+        }
+
+        return START_NOT_STICKY;
+    }
+    
+    
+    /**
+     * Provides a binder object that clients can use to perform operations on the queue of downloads, excepting the addition of new files. 
+     * 
+     * Implemented to perform cancellation, pause and resume of existing downloads.
+     */
+    @Override
+    public IBinder onBind(Intent arg0) {
+        return mBinder;
+    }
+
+
+    /**
+     * Called when ALL the bound clients were onbound.
+     */
+    @Override
+    public boolean onUnbind(Intent intent) {
+        ((FileDownloaderBinder)mBinder).clearListeners();
+        return false;   // not accepting rebinding (default behaviour)
+    }
+
+    
+    /**
+     *  Binder to let client components to perform operations on the queue of downloads.
+     * 
+     *  It provides by itself the available operations.
+     */
+    public class FileDownloaderBinder extends Binder implements OnDatatransferProgressListener {
+        
+        /** 
+         * Map of listeners that will be reported about progress of downloads from a {@link FileDownloaderBinder} instance 
+         */
+        private Map<String, OnDatatransferProgressListener> mBoundListeners = new HashMap<String, OnDatatransferProgressListener>();
+        
+        
+        /**
+         * Cancels a pending or current download of a remote file.
+         * 
+         * @param account       Owncloud account where the remote file is stored.
+         * @param file          A file in the queue of pending downloads
+         */
+        public void cancel(Account account, OCFile file) {
+            DownloadFileOperation download = null;
+            synchronized (mPendingDownloads) {
+                download = mPendingDownloads.remove(buildRemoteName(account, file));
+            }
+            if (download != null) {
+                download.cancel();
+            }
+        }
+        
+        
+        public void clearListeners() {
+            mBoundListeners.clear();
+        }
+
+
+        /**
+         * Returns True when the file described by 'file' in the ownCloud account 'account' is downloading or waiting to download.
+         * 
+         * If 'file' is a directory, returns 'true' if some of its descendant files is downloading or waiting to download. 
+         * 
+         * @param account       Owncloud account where the remote file is stored.
+         * @param file          A file that could be in the queue of downloads.
+         */
+        public boolean isDownloading(Account account, OCFile file) {
+            if (account == null || file == null) return false;
+            String targetKey = buildRemoteName(account, file);
+            synchronized (mPendingDownloads) {
+                if (file.isDirectory()) {
+                    // this can be slow if there are many downloads :(
+                    Iterator<String> it = mPendingDownloads.keySet().iterator();
+                    boolean found = false;
+                    while (it.hasNext() && !found) {
+                        found = it.next().startsWith(targetKey);
+                    }
+                    return found;
+                } else {
+                    return (mPendingDownloads.containsKey(targetKey));
+                }
+            }
+        }
+
+        
+        /**
+         * Adds a listener interested in the progress of the download for a concrete file.
+         * 
+         * @param listener      Object to notify about progress of transfer.    
+         * @param account       ownCloud account holding the file of interest.
+         * @param file          {@link OCfile} of interest for listener. 
+         */
+        public void addDatatransferProgressListener (OnDatatransferProgressListener listener, Account account, OCFile file) {
+            if (account == null || file == null || listener == null) return;
+            String targetKey = buildRemoteName(account, file);
+            mBoundListeners.put(targetKey, listener);
+        }
+        
+        
+        
+        /**
+         * Removes a listener interested in the progress of the download for a concrete file.
+         * 
+         * @param listener      Object to notify about progress of transfer.    
+         * @param account       ownCloud account holding the file of interest.
+         * @param file          {@link OCfile} of interest for listener. 
+         */
+        public void removeDatatransferProgressListener (OnDatatransferProgressListener listener, Account account, OCFile file) {
+            if (account == null || file == null || listener == null) return;
+            String targetKey = buildRemoteName(account, file);
+            if (mBoundListeners.get(targetKey) == listener) {
+                mBoundListeners.remove(targetKey);
+            }
+        }
+
+
+        @Override
+        public void onTransferProgress(long progressRate) {
+            // old way, should not be in use any more
+        }
+
+
+        @Override
+        public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer,
+                String fileName) {
+            String key = buildRemoteName(mCurrentDownload.getAccount(), mCurrentDownload.getFile());
+            OnDatatransferProgressListener boundListener = mBoundListeners.get(key);
+            if (boundListener != null) {
+                boundListener.onTransferProgress(progressRate, totalTransferredSoFar, totalToTransfer, fileName);
+            }
+        }
+        
+    }
+    
+    
+    /** 
+     * Download worker. Performs the pending downloads in the order they were requested. 
+     * 
+     * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}. 
+     */
+    private static class ServiceHandler extends Handler {
+        // don't make it a final class, and don't remove the static ; lint will warn about a possible memory leak
+        FileDownloader mService;
+        public ServiceHandler(Looper looper, FileDownloader service) {
+            super(looper);
+            if (service == null)
+                throw new IllegalArgumentException("Received invalid NULL in parameter 'service'");
+            mService = service;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            @SuppressWarnings("unchecked")
+            AbstractList<String> requestedDownloads = (AbstractList<String>) msg.obj;
+            if (msg.obj != null) {
+                Iterator<String> it = requestedDownloads.iterator();
+                while (it.hasNext()) {
+                    mService.downloadFile(it.next());
+                }
+            }
+            mService.stopSelf(msg.arg1);
+        }
+    }
+    
+    
+
+    /**
+     * Core download method: requests a file to download and stores it.
+     * 
+     * @param downloadKey   Key to access the download to perform, contained in mPendingDownloads 
+     */
+    private void downloadFile(String downloadKey) {
+        
+        synchronized(mPendingDownloads) {
+            mCurrentDownload = mPendingDownloads.get(downloadKey);
+        }
+        
+        if (mCurrentDownload != null) {
+            
+            notifyDownloadStart(mCurrentDownload);
+
+            /// prepare client object to send the request to the ownCloud server
+            if (mDownloadClient == null || !mLastAccount.equals(mCurrentDownload.getAccount())) {
+                mLastAccount = mCurrentDownload.getAccount();
+                mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());
+                mDownloadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());
+            }
+
+            /// perform the download
+            RemoteOperationResult downloadResult = null;
+            try {
+                downloadResult = mCurrentDownload.execute(mDownloadClient);
+                if (downloadResult.isSuccess()) {
+                    saveDownloadedFile();
+                }
+            
+            } finally {
+                synchronized(mPendingDownloads) {
+                    mPendingDownloads.remove(downloadKey);
+                }
+            }
+
+            
+            /// notify result
+            notifyDownloadResult(mCurrentDownload, downloadResult);
+            
+            sendBroadcastDownloadFinished(mCurrentDownload, downloadResult);
+        }
+    }
+
+
+    /**
+     * Updates the OC File after a successful download.
+     */
+    private void saveDownloadedFile() {
+        OCFile file = mCurrentDownload.getFile();
+        long syncDate = System.currentTimeMillis();
+        file.setLastSyncDateForProperties(syncDate);
+        file.setLastSyncDateForData(syncDate);
+        file.setModificationTimestamp(mCurrentDownload.getModificationTimestamp());
+        file.setModificationTimestampAtLastSyncForData(mCurrentDownload.getModificationTimestamp());
+        // file.setEtag(mCurrentDownload.getEtag());    // TODO Etag, where available
+        file.setMimetype(mCurrentDownload.getMimeType());
+        file.setStoragePath(mCurrentDownload.getSavePath());
+        file.setFileLength((new File(mCurrentDownload.getSavePath()).length()));
+        mStorageManager.saveFile(file);
+    }
+
+
+    /**
+     * Creates a status notification to show the download progress
+     * 
+     * @param download  Download operation starting.
+     */
+    private void notifyDownloadStart(DownloadFileOperation download) {
+        /// create status notification with a progress bar
+        mLastPercent = 0;
+        mNotification = new Notification(R.drawable.icon, getString(R.string.downloader_download_in_progress_ticker), System.currentTimeMillis());
+        mNotification.flags |= Notification.FLAG_ONGOING_EVENT;
+        mNotification.contentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.progressbar_layout);
+        mNotification.contentView.setProgressBar(R.id.status_progress, 100, 0, download.getSize() < 0);
+        mNotification.contentView.setTextViewText(R.id.status_text, String.format(getString(R.string.downloader_download_in_progress_content), 0, new File(download.getSavePath()).getName()));
+        mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon);
+        
+        /// includes a pending intent in the notification showing the details view of the file
+        Intent showDetailsIntent = null;
+        if (PreviewImageFragment.canBePreviewed(download.getFile())) {
+            showDetailsIntent = new Intent(this, PreviewImageActivity.class);
+        } else {
+            showDetailsIntent = new Intent(this, FileDetailActivity.class);
+        }
+        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, download.getFile());
+        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, download.getAccount());
+        showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0);
+        
+        mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification);
+    }
+
+    
+    /**
+     * Callback method to update the progress bar in the status notification.
+     */
+    @Override
+    public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String fileName) {
+        int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));
+        if (percent != mLastPercent) {
+          mNotification.contentView.setProgressBar(R.id.status_progress, 100, percent, totalToTransfer < 0);
+          String text = String.format(getString(R.string.downloader_download_in_progress_content), percent, fileName);
+          mNotification.contentView.setTextViewText(R.id.status_text, text);
+          mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotification);
+        }
+        mLastPercent = percent;
+    }
+    
+    
+    /**
+     * Callback method to update the progress bar in the status notification (old version)
+     */
+    @Override
+    public void onTransferProgress(long progressRate) {
+        // NOTHING TO DO HERE ANYMORE
+    }
+    
+
+    /**
+     * Updates the status notification with the result of a download operation.
+     * 
+     * @param downloadResult    Result of the download operation.
+     * @param download          Finished download operation
+     */
+    private void notifyDownloadResult(DownloadFileOperation download, RemoteOperationResult downloadResult) {
+        mNotificationManager.cancel(R.string.downloader_download_in_progress_ticker);
+        if (!downloadResult.isCancelled()) {
+            int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker : R.string.downloader_download_failed_ticker;
+            int contentId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_content : R.string.downloader_download_failed_content;
+            Notification finalNotification = new Notification(R.drawable.icon, getString(tickerId), System.currentTimeMillis());
+            finalNotification.flags |= Notification.FLAG_AUTO_CANCEL;
+            Intent showDetailsIntent = null;
+            if (downloadResult.isSuccess()) {
+                if (PreviewImageFragment.canBePreviewed(download.getFile())) {
+                    showDetailsIntent = new Intent(this, PreviewImageActivity.class);
+                } else {
+                    showDetailsIntent = new Intent(this, FileDetailActivity.class);
+                }
+                showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, download.getFile());
+                showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, download.getAccount());
+                showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                
+            } else {
+                // TODO put something smart in showDetailsIntent
+                showDetailsIntent = new Intent();
+            }
+            finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0);
+            finalNotification.setLatestEventInfo(getApplicationContext(), getString(tickerId), String.format(getString(contentId), new File(download.getSavePath()).getName()), finalNotification.contentIntent);
+            mNotificationManager.notify(tickerId, finalNotification);
+        }
+    }
+    
+    
+    /**
+     * Sends a broadcast when a download finishes in order to the interested activities can update their view
+     * 
+     * @param download          Finished download operation
+     * @param downloadResult    Result of the download operation
+     */
+    private void sendBroadcastDownloadFinished(DownloadFileOperation download, RemoteOperationResult downloadResult) {
+        Intent end = new Intent(DOWNLOAD_FINISH_MESSAGE);
+        end.putExtra(EXTRA_DOWNLOAD_RESULT, downloadResult.isSuccess());
+        end.putExtra(ACCOUNT_NAME, download.getAccount().name);
+        end.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());
+        end.putExtra(EXTRA_FILE_PATH, download.getSavePath());
+        sendStickyBroadcast(end);
+    }
+    
+    
+    /**
+     * Sends a broadcast when a new download is added to the queue.
+     * 
+     * @param download          Added download operation
+     */
+    private void sendBroadcastNewDownload(DownloadFileOperation download) {
+        Intent added = new Intent(DOWNLOAD_ADDED_MESSAGE);
+        added.putExtra(ACCOUNT_NAME, download.getAccount().name);
+        added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());
+        added.putExtra(EXTRA_FILE_PATH, download.getSavePath());
+        sendStickyBroadcast(added);
+    }
+
+}
index d4bf24d..635571f 100644 (file)
@@ -23,6 +23,7 @@ import java.io.File;
 import java.util.HashMap;
 import java.util.Map;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
@@ -83,7 +84,7 @@ public class FileObserverService extends Service {
         super.onDestroy();
         unregisterReceiver(mDownloadReceiver);
         mObserversMap = null;   // TODO study carefully the life cycle of Services to grant the best possible observance
-        Log.d(TAG, "Bye, bye");
+        Log_OC.d(TAG, "Bye, bye");
     }
     
     
@@ -102,7 +103,7 @@ public class FileObserverService extends Service {
         }
             
         if (!intent.hasExtra(KEY_FILE_CMD)) {
-            Log.e(TAG, "No KEY_FILE_CMD argument given");
+            Log_OC.e(TAG, "No KEY_FILE_CMD argument given");
             return Service.START_STICKY;
         }
 
@@ -119,7 +120,7 @@ public class FileObserverService extends Service {
                                     (Account)intent.getParcelableExtra(KEY_CMD_ARG_ACCOUNT));
                 break;
             default:
-                Log.wtf(TAG, "Incorrect key given");
+                Log_OC.wtf(TAG, "Incorrect key given");
         }
 
         return Service.START_STICKY;
@@ -166,7 +167,7 @@ public class FileObserverService extends Service {
             mObserversMap.put(path, observer);
             if (new File(path).exists()) {
                 observer.startWatching();
-                Log.d(TAG, "Started watching file " + path);
+                Log_OC.d(TAG, "Started watching file " + path);
             }
             
         } while (c.moveToNext());
@@ -189,7 +190,7 @@ public class FileObserverService extends Service {
      */
     private void addObservedFile(OCFile file, Account account) {
         if (file == null) {
-            Log.e(TAG, "Trying to add a NULL file to observer");
+            Log_OC.e(TAG, "Trying to add a NULL file to observer");
             return;
         }
         String localPath = file.getStoragePath();
@@ -204,11 +205,11 @@ public class FileObserverService extends Service {
                                                     getApplicationContext(), 
                                                     OwnCloudFileObserver.CHANGES_ONLY);
             mObserversMap.put(localPath, observer);
-            Log.d(TAG, "Observer added for path " + localPath);
+            Log_OC.d(TAG, "Observer added for path " + localPath);
         
             if (file.isDown()) {
                 observer.startWatching();
-                Log.d(TAG, "Started watching " + localPath);
+                Log_OC.d(TAG, "Started watching " + localPath);
             }   // else - the observance can't be started on a file not already down; mDownloadReceiver will get noticed when the download of the file finishes
         }
         
@@ -229,7 +230,7 @@ public class FileObserverService extends Service {
      */
     private void removeObservedFile(OCFile file, Account account) {
         if (file == null) {
-            Log.e(TAG, "Trying to remove a NULL file");
+            Log_OC.e(TAG, "Trying to remove a NULL file");
             return;
         }
         String localPath = file.getStoragePath();
@@ -241,7 +242,7 @@ public class FileObserverService extends Service {
         if (observer != null) {
             observer.stopWatching();
             mObserversMap.remove(observer);
-            Log.d(TAG, "Stopped watching " + localPath);
+            Log_OC.d(TAG, "Stopped watching " + localPath);
         }
         
     }
@@ -263,11 +264,11 @@ public class FileObserverService extends Service {
                 if (intent.getAction().equals(FileDownloader.DOWNLOAD_FINISH_MESSAGE) &&
                         new File(downloadPath).exists()) {  // the download could be successful, or not; in both cases, the file could be down, due to a former download or upload   
                     observer.startWatching();
-                    Log.d(TAG, "Watching again " + downloadPath);
+                    Log_OC.d(TAG, "Watching again " + downloadPath);
                 
                 } else if (intent.getAction().equals(FileDownloader.DOWNLOAD_ADDED_MESSAGE)) {
                     observer.stopWatching();
-                    Log.d(TAG, "Disabling observance of " + downloadPath);
+                    Log_OC.d(TAG, "Disabling observance of " + downloadPath);
                 } 
             }
         }
index 9d2bbcf..efdae3d 100644 (file)
@@ -51,6 +51,7 @@ import android.webkit.MimeTypeMap;
 import android.widget.RemoteViews;
 import android.widget.Toast;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 import com.owncloud.android.authenticator.AccountAuthenticator;
 import com.owncloud.android.datamodel.FileDataStorageManager;
@@ -151,7 +152,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     @Override
     public void onCreate() {
         super.onCreate();
-        Log.i(TAG, "mPendingUploads size:" + mPendingUploads.size());
+        Log_OC.i(TAG, "mPendingUploads size:" + mPendingUploads.size());
         mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
         HandlerThread thread = new HandlerThread("FileUploaderThread", Process.THREAD_PRIORITY_BACKGROUND);
         thread.start();
@@ -171,12 +172,12 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     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))) {
-            Log.e(TAG, "Not enough information provided in intent");
+            Log_OC.e(TAG, "Not enough information provided in intent");
             return Service.START_NOT_STICKY;
         }
         int uploadType = intent.getIntExtra(KEY_UPLOAD_TYPE, -1);
         if (uploadType == -1) {
-            Log.e(TAG, "Incorrect upload type provided");
+            Log_OC.e(TAG, "Incorrect upload type provided");
             return Service.START_NOT_STICKY;
         }
         Account account = intent.getParcelableExtra(KEY_ACCOUNT);
@@ -227,20 +228,20 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         }
 
         if (intent.hasExtra(KEY_FILE) && files == null) {
-            Log.e(TAG, "Incorrect array for OCFiles provided in upload intent");
+            Log_OC.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");
+                Log_OC.e(TAG, "Incorrect array for local paths provided in upload intent");
                 return Service.START_NOT_STICKY;
             }
             if (remotePaths == null) {
-                Log.e(TAG, "Incorrect array for remote paths provided in upload intent");
+                Log_OC.e(TAG, "Incorrect array for remote paths provided in upload intent");
                 return Service.START_NOT_STICKY;
             }
             if (localPaths.length != remotePaths.length) {
-                Log.e(TAG, "Different number of remote paths and local paths!");
+                Log_OC.e(TAG, "Different number of remote paths and local paths!");
                 return Service.START_NOT_STICKY;
             }
 
@@ -280,15 +281,15 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
             }
 
         } catch (IllegalArgumentException e) {
-            Log.e(TAG, "Not enough information provided in intent: " + e.getMessage());
+            Log_OC.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());
+            Log_OC.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);
+            Log_OC.e(TAG, "Unexpected exception while processing upload intent", e);
             return START_NOT_STICKY;
 
         }
@@ -299,7 +300,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
             msg.obj = requestedUploads;
             mServiceHandler.sendMessage(msg);
         }
-        Log.i(TAG, "mPendingUploads size:" + mPendingUploads.size());
+        Log_OC.i(TAG, "mPendingUploads size:" + mPendingUploads.size());
         return Service.START_NOT_STICKY;
     }
 
@@ -516,7 +517,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
             } finally {
                 synchronized (mPendingUploads) {
                     mPendingUploads.remove(uploadKey);
-                    Log.i(TAG, "Remove CurrentUploadItem from pending upload Item Map.");
+                    Log_OC.i(TAG, "Remove CurrentUploadItem from pending upload Item Map.");
                 }
             }
 
@@ -562,12 +563,12 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
             }
 
             result = new RemoteOperationResult(isMultiStatus, status);
-            Log.i(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": "
+            Log_OC.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() + ": "
+            Log_OC.e(TAG, "Update: synchronizing properties for uploaded " + mCurrentUpload.getRemotePath() + ": "
                     + result.getLogMessage(), e);
 
         } finally {
@@ -642,7 +643,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                 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);
+                Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + remotePath);
             }
         }
         if (mimeType == null) {
@@ -736,7 +737,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
      * @param upload Finished upload operation
      */
     private void notifyUploadResult(RemoteOperationResult uploadResult, UploadFileOperation upload) {
-        Log.d(TAG, "NotifyUploadResult with resultCode: " + uploadResult.getCode());
+        Log_OC.d(TAG, "NotifyUploadResult with resultCode: " + uploadResult.getCode());
         if (uploadResult.isCancelled()) {
             // / cancelled operation -> silent removal of progress notification
             mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker);
index 8ebcef4..b2eab0d 100644 (file)
@@ -23,16 +23,16 @@ import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.utils.FileStorageUtils;
+import com.owncloud.android.network.OwnCloudClientUtils;
+
+import eu.alefzero.webdav.WebdavClient;
+
 import android.accounts.Account;
 import android.app.Service;
 import android.content.Intent;
 import android.os.IBinder;
-import android.util.Log;
-
-import com.owncloud.android.network.OwnCloudClientUtils;
-import com.owncloud.android.utils.FileStorageUtils;
-
-import eu.alefzero.webdav.WebdavClient;
 
 public class InstantUploadService extends Service {
 
@@ -57,7 +57,7 @@ public class InstantUploadService extends Service {
         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");
+            Log_OC.w(TAG, "Not all required information was provided, abording");
             return Service.START_NOT_STICKY;
         }
 
@@ -75,7 +75,7 @@ public class InstantUploadService extends Service {
 
         // starting new thread for new download doesnt seems like a good idea
         // maybe some thread pool or single background thread would be better
-        Log.d(TAG, "Starting instant upload thread");
+        Log_OC.d(TAG, "Starting instant upload thread");
         new Thread(mUploaderRunnable).start();
 
         return Service.START_STICKY;
index a2b131f..0803f47 100644 (file)
@@ -18,6 +18,8 @@
  */
 package com.owncloud.android.location;
 
+import com.owncloud.android.Log_OC;
+
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningServiceInfo;
 import android.content.BroadcastReceiver;
@@ -60,10 +62,10 @@ public class LocationServiceLauncherReciever extends BroadcastReceiver {
         deviceTrackingIntent
                 .setAction("com.owncloud.android.location.LocationUpdateService");
         if (!isDeviceTrackingServiceRunning(context) && trackDevice) {
-            Log.d(TAG, "Starting device tracker service");
+            Log_OC.d(TAG, "Starting device tracker service");
             context.startService(deviceTrackingIntent);
         } else if (isDeviceTrackingServiceRunning(context) && !trackDevice) {
-            Log.d(TAG, "Stopping device tracker service");
+            Log_OC.d(TAG, "Stopping device tracker service");
             context.stopService(deviceTrackingIntent);
         }
     }
index 1b6b28a..c468fbd 100644 (file)
@@ -31,6 +31,7 @@ import android.preference.PreferenceManager;
 import android.util.Log;
 import android.widget.Toast;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 
 public class LocationUpdateService extends IntentService implements
@@ -76,7 +77,7 @@ public class LocationUpdateService extends IntentService implements
 
         // If we do shall track the device -> Stop
         if (!trackDevice) {
-            Log.d(TAG, "Devicetracking is disabled");
+            Log_OC.d(TAG, "Devicetracking is disabled");
             stopSelf();
             return;
         }
@@ -87,7 +88,7 @@ public class LocationUpdateService extends IntentService implements
 
     @Override
     public void onLocationChanged(Location location) {
-        Log.d(TAG, "Location changed: " + location);
+        Log_OC.d(TAG, "Location changed: " + location);
 
     }
 
index c206ca7..59a125d 100644 (file)
@@ -40,6 +40,8 @@ import org.apache.commons.httpclient.params.HttpConnectionParams;
 import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
 import org.apache.http.conn.ssl.X509HostnameVerifier;
 
+import com.owncloud.android.Log_OC;
+
 import android.util.Log;
 
 /**
@@ -104,13 +106,13 @@ public class AdvancedSslSocketFactory implements ProtocolSocketFactory {
             final InetAddress localAddress, final int localPort,
             final HttpConnectionParams params) throws IOException,
             UnknownHostException, ConnectTimeoutException {
-        Log.d(TAG, "Creating SSL Socket with remote " + host + ":" + port + ", local " + localAddress + ":" + localPort + ", params: " + params);
+        Log_OC.d(TAG, "Creating SSL Socket with remote " + host + ":" + port + ", local " + localAddress + ":" + localPort + ", params: " + params);
         if (params == null) {
             throw new IllegalArgumentException("Parameters may not be null");
         } 
         int timeout = params.getConnectionTimeout();
         SocketFactory socketfactory = mSslContext.getSocketFactory();
-        Log.d(TAG, " ... with connection timeout " + timeout + " and socket timeout " + params.getSoTimeout());
+        Log_OC.d(TAG, " ... with connection timeout " + timeout + " and socket timeout " + params.getSoTimeout());
         Socket socket = socketfactory.createSocket();
         SocketAddress localaddr = new InetSocketAddress(localAddress, localPort);
         SocketAddress remoteaddr = new InetSocketAddress(host, port);
@@ -126,7 +128,7 @@ public class AdvancedSslSocketFactory implements ProtocolSocketFactory {
      */
     public Socket createSocket(String host, int port) throws IOException,
             UnknownHostException {
-        Log.d(TAG, "Creating SSL Socket with remote " + host + ":" + port);
+        Log_OC.d(TAG, "Creating SSL Socket with remote " + host + ":" + port);
         Socket socket = mSslContext.getSocketFactory().createSocket(host, port);
         verifyPeerIdentity(host, port, socket);
         return socket; 
index d3c7924..671e98b 100644 (file)
@@ -32,6 +32,8 @@ import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
+import com.owncloud.android.Log_OC;
+
 import android.util.Log;
 
 /**
@@ -139,7 +141,7 @@ public class AdvancedX509TrustManager implements X509TrustManager {
         try {
             return (mKnownServersKeyStore.getCertificateAlias(cert) != null);
         } catch (KeyStoreException e) {
-            Log.d(TAG, "Fail while checking certificate in the known-servers store");
+            Log_OC.d(TAG, "Fail while checking certificate in the known-servers store");
             return false;
         }
     }
index 1984413..bed7aff 100644 (file)
@@ -38,6 +38,7 @@ import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
 import org.apache.http.conn.ssl.X509HostnameVerifier;
 
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
 
 import eu.alefzero.webdav.WebdavClient;
 
@@ -75,7 +76,7 @@ public class OwnCloudClientUtils {
      * @return          A WebdavClient object ready to be used
      */
     public static WebdavClient createOwnCloudClient (Account account, Context context) {
-        Log.d(TAG, "Creating WebdavClient associated to " + account.name);
+        Log_OC.d(TAG, "Creating WebdavClient associated to " + account.name);
        
         Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(context, account));
         WebdavClient client = createOwnCloudClient(uri, context);
@@ -100,7 +101,7 @@ public class OwnCloudClientUtils {
      * @return          A WebdavClient object ready to be used
      */
     public static WebdavClient createOwnCloudClient(Uri uri, String username, String password, Context context) {
-        Log.d(TAG, "Creating WebdavClient for " + username + "@" + uri);
+        Log_OC.d(TAG, "Creating WebdavClient for " + username + "@" + uri);
         
         WebdavClient client = createOwnCloudClient(uri, context);
         
@@ -118,16 +119,16 @@ public class OwnCloudClientUtils {
      * @return          A WebdavClient object ready to be used
      */
     public static WebdavClient createOwnCloudClient(Uri uri, Context context) {
-        Log.d(TAG, "Creating WebdavClient for " + uri);
+        Log_OC.d(TAG, "Creating WebdavClient for " + uri);
         
         //allowSelfsignedCertificates(true);
         try {
             registerAdvancedSslContext(true, context);
         }  catch (GeneralSecurityException e) {
-            Log.e(TAG, "Advanced SSL Context could not be loaded. Default SSL management in the system will be used for HTTPS connections", e);
+            Log_OC.e(TAG, "Advanced SSL Context could not be loaded. Default SSL management in the system will be used for HTTPS connections", e);
             
         } catch (IOException e) {
-            Log.e(TAG, "The local server truststore could not be read. Default SSL management in the system will be used for HTTPS connections", e);
+            Log_OC.e(TAG, "The local server truststore could not be read. Default SSL management in the system will be used for HTTPS connections", e);
         }
         
         WebdavClient client = new WebdavClient(getMultiThreadedConnManager());
@@ -205,7 +206,7 @@ public class OwnCloudClientUtils {
             //mKnownServersStore = KeyStore.getInstance("BKS");
             mKnownServersStore = KeyStore.getInstance(KeyStore.getDefaultType());
             File localTrustStoreFile = new File(context.getFilesDir(), LOCAL_TRUSTSTORE_FILENAME);
-            Log.d(TAG, "Searching known-servers store at " + localTrustStoreFile.getAbsolutePath());
+            Log_OC.d(TAG, "Searching known-servers store at " + localTrustStoreFile.getAbsolutePath());
             if (localTrustStoreFile.exists()) {
                 InputStream in = new FileInputStream(localTrustStoreFile);
                 try {
index d421803..647bec0 100644 (file)
@@ -28,6 +28,7 @@ import java.util.Random;
 import org.apache.commons.httpclient.HttpException;
 import org.apache.commons.httpclient.methods.PutMethod;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.network.ProgressiveDataTransferer;
 
@@ -75,7 +76,7 @@ public class ChunkedUploadFileOperation extends UploadFileOperation {
                 mPutMethod.setRequestEntity(mEntity);
                 status = client.executeMethod(mPutMethod);
                 client.exhaustResponse(mPutMethod.getResponseBodyAsStream());
-                Log.d(TAG, "Upload of " + getStoragePath() + " to " + getRemotePath() + ", chunk index " + chunkIndex + ", count " + chunkCount + ", HTTP result status " + status);
+                Log_OC.d(TAG, "Upload of " + getStoragePath() + " to " + getRemotePath() + ", chunk index " + chunkIndex + ", count " + chunkCount + ", HTTP result status " + status);
                 if (!isSuccess(status))
                     break;
             }
index f8ede26..d83de76 100644 (file)
@@ -24,6 +24,7 @@ import org.json.JSONException;
 import org.json.JSONObject;
 
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.utils.OwnCloudVersion;
 
 import eu.alefzero.webdav.WebdavClient;
@@ -96,13 +97,13 @@ public class ConnectionCheckOperation extends RemoteOperation {
         }
         
         if (mLatestResult.isSuccess()) {
-            Log.i(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage());
+            Log_OC.i(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage());
             
         } else if (mLatestResult.getException() != null) {
-            Log.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage(), mLatestResult.getException());
+            Log_OC.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage(), mLatestResult.getException());
             
         } else {
-            Log.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage());
+            Log_OC.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage());
         }
 
         return retval;
@@ -127,7 +128,7 @@ public class ConnectionCheckOperation extends RemoteOperation {
             client.setBaseUri(Uri.parse("https://" + mUrl + AccountUtils.STATUS_PATH));
             boolean httpsSuccess = tryConnection(client, "https://" + mUrl + AccountUtils.STATUS_PATH); 
             if (!httpsSuccess && !mLatestResult.isSslRecoverableException()) {
-                Log.d(TAG, "establishing secure connection failed, trying non secure connection");
+                Log_OC.d(TAG, "establishing secure connection failed, trying non secure connection");
                 client.setBaseUri(Uri.parse("http://" + mUrl + AccountUtils.STATUS_PATH));
                 tryConnection(client, "http://" + mUrl + AccountUtils.STATUS_PATH);
             }
index da6b270..0aa9d1e 100644 (file)
@@ -33,6 +33,7 @@ import org.apache.commons.httpclient.HttpException;
 import org.apache.commons.httpclient.methods.GetMethod;
 import org.apache.http.HttpStatus;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.operations.RemoteOperation;
 import com.owncloud.android.operations.RemoteOperationResult;
@@ -104,7 +105,7 @@ public class DownloadFileOperation extends RemoteOperation {
                     .getMimeTypeFromExtension(
                             mFile.getRemotePath().substring(mFile.getRemotePath().lastIndexOf('.') + 1));
             } catch (IndexOutOfBoundsException e) {
-                Log.e(TAG, "Trying to find out MIME type of a file without extension: " + mFile.getRemotePath());
+                Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + mFile.getRemotePath());
             }
         }
         if (mimeType == null) {
@@ -156,11 +157,11 @@ public class DownloadFileOperation extends RemoteOperation {
                 result = new RemoteOperationResult(RemoteOperationResult.ResultCode.LOCAL_STORAGE_NOT_MOVED);
             else
                 result = new RemoteOperationResult(isSuccess(status), status);
-            Log.i(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage());
+            Log_OC.i(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage());
             
         } catch (Exception e) {
             result = new RemoteOperationResult(e);
-            Log.e(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage(), e);
+            Log_OC.e(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage(), e);
         }
         
         return result;
index 80f4097..4203f6f 100644 (file)
@@ -23,6 +23,7 @@ import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
 
 import android.util.Log;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 
@@ -91,11 +92,11 @@ public class RemoveFileOperation extends RemoteOperation {
             }
             delete.getResponseBodyAsString();   // exhaust the response, although not interesting
             result = new RemoteOperationResult((delete.succeeded() || status == HttpStatus.SC_NOT_FOUND), status);
-            Log.i(TAG, "Remove " + mFileToRemove.getRemotePath() + ": " + result.getLogMessage());
+            Log_OC.i(TAG, "Remove " + mFileToRemove.getRemotePath() + ": " + result.getLogMessage());
             
         } catch (Exception e) {
             result = new RemoteOperationResult(e);
-            Log.e(TAG, "Remove " + mFileToRemove.getRemotePath() + ": " + result.getLogMessage(), e);
+            Log_OC.e(TAG, "Remove " + mFileToRemove.getRemotePath() + ": " + result.getLogMessage(), e);
             
         } finally {
             if (delete != null)
index 41233f1..bc2c6e0 100644 (file)
@@ -27,6 +27,7 @@ import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
 import android.accounts.Account;
 import android.util.Log;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
@@ -138,11 +139,11 @@ public class RenameFileOperation extends RemoteOperation {
             
             move.getResponseBodyAsString(); // exhaust response, although not interesting
             result = new RemoteOperationResult(move.succeeded(), status);
-            Log.i(TAG, "Rename " + mFile.getRemotePath() + " to " + mNewRemotePath + ": " + result.getLogMessage());
+            Log_OC.i(TAG, "Rename " + mFile.getRemotePath() + " to " + mNewRemotePath + ": " + result.getLogMessage());
             
         } catch (Exception e) {
             result = new RemoteOperationResult(e);
-            Log.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((mNewRemotePath==null) ? mNewName : mNewRemotePath) + ": " + result.getLogMessage(), e);
+            Log_OC.e(TAG, "Rename " + mFile.getRemotePath() + " to " + ((mNewRemotePath==null) ? mNewName : mNewRemotePath) + ": " + result.getLogMessage(), e);
             
         } finally {
             if (move != null)
@@ -206,7 +207,7 @@ public class RenameFileOperation extends RemoteOperation {
         try {
             testFile.createNewFile();   // return value is ignored; it could be 'false' because the file already existed, that doesn't invalidate the name
         } catch (IOException e) {
-            Log.i(TAG, "Test for validity of name " + mNewName + " in the file system failed");
+            Log_OC.i(TAG, "Test for validity of name " + mNewName + " in the file system failed");
             return false;
         }
         boolean result = (testFile.exists() && testFile.isFile());
index 4ed56d7..0a387ae 100644 (file)
@@ -28,6 +28,7 @@ import android.content.Context;
 import android.content.Intent;
 import android.util.Log;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileDownloader;
@@ -158,11 +159,11 @@ public class SynchronizeFileOperation extends RemoteOperation {
           
             }
             
-            Log.i(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() + ": " + result.getLogMessage());
+            Log_OC.i(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() + ": " + result.getLogMessage());
           
         } catch (Exception e) {
             result = new RemoteOperationResult(e);
-            Log.e(TAG, "Synchronizing " + mAccount.name + ", file " + (mLocalFile != null ? mLocalFile.getRemotePath() : "NULL") + ": " + result.getLogMessage(), result.getException());
+            Log_OC.e(TAG, "Synchronizing " + mAccount.name + ", file " + (mLocalFile != null ? mLocalFile.getRemotePath() : "NULL") + ": " + result.getLogMessage(), result.getException());
 
         } finally {
             if (propfind != null)
index 977460b..96131a2 100644 (file)
@@ -37,6 +37,7 @@ import android.accounts.Account;
 import android.content.Context;
 import android.util.Log;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
@@ -132,7 +133,7 @@ public class SynchronizeFolderOperation extends RemoteOperation {
         // code before in FileSyncAdapter.fetchData
         PropFindMethod query = null;
         try {
-            Log.d(TAG, "Synchronizing " + mAccount.name + ", fetching files in " + mRemotePath);
+            Log_OC.d(TAG, "Synchronizing " + mAccount.name + ", fetching files in " + mRemotePath);
             
             // remote request 
             query = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath));
@@ -209,9 +210,9 @@ public class SynchronizeFolderOperation extends RemoteOperation {
                         } else {
                             mFailsInFavouritesFound++;
                             if (contentsResult.getException() != null) {
-                                Log.d(TAG, "Error while synchronizing favourites : " +  contentsResult.getLogMessage(), contentsResult.getException());
+                                Log_OC.d(TAG, "Error while synchronizing favourites : " +  contentsResult.getLogMessage(), contentsResult.getException());
                             } else {
-                                Log.d(TAG, "Error while synchronizing favourites : " + contentsResult.getLogMessage());
+                                Log_OC.d(TAG, "Error while synchronizing favourites : " + contentsResult.getLogMessage());
                             }
                         }
                     }   // won't let these fails break the synchronization process
@@ -225,7 +226,7 @@ public class SynchronizeFolderOperation extends RemoteOperation {
                 for (int i=0; i < mChildren.size(); ) {
                     file = mChildren.get(i);
                     if (file.getLastSyncDateForProperties() != mCurrentSyncTime) {
-                        Log.d(TAG, "removing file: " + file);
+                        Log_OC.d(TAG, "removing file: " + file);
                         mStorageManager.removeFile(file, (file.isDown() && file.getStoragePath().startsWith(currentSavePath)));
                         mChildren.remove(i);
                     } else {
@@ -248,12 +249,12 @@ public class SynchronizeFolderOperation extends RemoteOperation {
             } else {
                 result = new RemoteOperationResult(false, status);
             }
-            Log.i(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage());
+            Log_OC.i(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage());
             
             
         } catch (Exception e) {
             result = new RemoteOperationResult(e);
-            Log.e(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage(), result.getException());
+            Log_OC.e(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage(), result.getException());
 
         } finally {
             if (query != null)
@@ -329,7 +330,7 @@ public class SynchronizeFolderOperation extends RemoteOperation {
                     file.setStoragePath(expectedPath);
                     
                 } catch (Exception e) {
-                    Log.e(TAG, "Exception while copying foreign file " + expectedPath, e);
+                    Log_OC.e(TAG, "Exception while copying foreign file " + expectedPath, e);
                     mForgottenLocalFiles.put(file.getRemotePath(), storagePath);
                     file.setStoragePath(null);
                     
@@ -337,12 +338,12 @@ public class SynchronizeFolderOperation extends RemoteOperation {
                     try {
                         if (in != null) in.close();
                     } catch (Exception e) {
-                        Log.d(TAG, "Weird exception while closing input stream for " + storagePath + " (ignoring)", e);
+                        Log_OC.d(TAG, "Weird exception while closing input stream for " + storagePath + " (ignoring)", e);
                     }
                     try {
                         if (out != null) out.close();
                     } catch (Exception e) {
-                        Log.d(TAG, "Weird exception while closing output stream for " + expectedPath + " (ignoring)", e);
+                        Log_OC.d(TAG, "Weird exception while closing output stream for " + expectedPath + " (ignoring)", e);
                     }
                 }
             }
index 08a9c15..2316881 100644 (file)
@@ -29,6 +29,7 @@ import android.content.Context;
 import android.util.Log;
 
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.authenticator.AccountAuthenticator;
 import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.utils.OwnCloudVersion;
@@ -76,11 +77,11 @@ public class UpdateOCVersionOperation extends RemoteOperation {
                         OwnCloudVersion ocver = new OwnCloudVersion(json.getString("version"));
                         if (ocver.isVersionValid()) {
                             accountMngr.setUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION, ocver.toString());
-                            Log.d(TAG, "Got new OC version " + ocver.toString());
+                            Log_OC.d(TAG, "Got new OC version " + ocver.toString());
                             result = new RemoteOperationResult(ResultCode.OK);
                             
                         } else {
-                            Log.w(TAG, "Invalid version number received from server: " + json.getString("version"));
+                            Log_OC.w(TAG, "Invalid version number received from server: " + json.getString("version"));
                             result = new RemoteOperationResult(RemoteOperationResult.ResultCode.BAD_OC_VERSION);
                         }
                     }
@@ -89,15 +90,15 @@ public class UpdateOCVersionOperation extends RemoteOperation {
                     result = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
                 }
             }
-            Log.i(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage());
+            Log_OC.i(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage());
             
         } catch (JSONException e) {
             result = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
-            Log.e(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage(), e);
+            Log_OC.e(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage(), e);
                 
         } catch (Exception e) {
             result = new RemoteOperationResult(e);
-            Log.e(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage(), e);
+            Log_OC.e(TAG, "Check for update of ownCloud server version at " + client.getBaseUri() + ": " + result.getLogMessage(), e);
             
         } finally {
             if (get != null) 
index 0dfb72c..77c0e07 100644 (file)
@@ -33,8 +33,8 @@ import org.apache.commons.httpclient.methods.PutMethod;
 import org.apache.commons.httpclient.methods.RequestEntity;
 import org.apache.http.HttpStatus;
 
+import com.owncloud.android.Log_OC;
 import android.accounts.Account;
-import android.util.Log;
 
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileUploader;
@@ -246,15 +246,13 @@ public class UploadFileOperation extends RemoteOperation {
                                 if (in != null)
                                     in.close();
                             } catch (Exception e) {
-                                Log.d(TAG, "Weird exception while closing input stream for " + mOriginalStoragePath
-                                        + " (ignoring)", e);
+                                Log_OC.d(TAG, "Weird exception while closing input stream for " + mOriginalStoragePath + " (ignoring)", e);
                             }
                             try {
                                 if (out != null)
                                     out.close();
                             } catch (Exception e) {
-                                Log.d(TAG, "Weird exception while closing output stream for " + expectedPath
-                                        + " (ignoring)", e);
+                                Log_OC.d(TAG, "Weird exception while closing output stream for " + expectedPath + " (ignoring)", e);
                             }
                         }
                     }
@@ -322,8 +320,7 @@ public class UploadFileOperation extends RemoteOperation {
                 temporalFile.delete();
             }
             if (result.isSuccess()) {
-                Log.i(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage());
-
+                Log_OC.i(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage());
             } else {
                 if (result.getException() != null) {
                     String complement = "";
@@ -333,12 +330,9 @@ public class UploadFileOperation extends RemoteOperation {
                         complement = " (while copying local file to " + FileStorageUtils.getSavePath(mAccount.name)
                                 + ")";
                     }
-                    Log.e(TAG,
-                            "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage()
-                                    + complement, result.getException());
+                    Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage() + complement, result.getException());
                 } else {
-                    Log.e(TAG,
-                            "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage());
+                    Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage());
                 }
             }
         }
index 5e54341..aedb568 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.providers;\r
-\r
-import java.util.HashMap;\r
-\r
-import com.owncloud.android.db.ProviderMeta;\r
-import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;\r
-\r
-\r
-import android.content.ContentProvider;\r
-import android.content.ContentUris;\r
-import android.content.ContentValues;\r
-import android.content.Context;\r
-import android.content.UriMatcher;\r
-import android.database.Cursor;\r
-import android.database.SQLException;\r
-import android.database.sqlite.SQLiteDatabase;\r
-import android.database.sqlite.SQLiteOpenHelper;\r
-import android.database.sqlite.SQLiteQueryBuilder;\r
-import android.net.Uri;\r
-import android.text.TextUtils;\r
-import android.util.Log;\r
-\r
-/**\r
- * The ContentProvider for the ownCloud App.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class FileContentProvider extends ContentProvider {\r
-\r
-    private DataBaseHelper mDbHelper;\r
-\r
-    private static HashMap<String, String> mProjectionMap;\r
-    static {\r
-        mProjectionMap = new HashMap<String, String>();\r
-        mProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID);\r
-        mProjectionMap.put(ProviderTableMeta.FILE_PARENT,\r
-                ProviderTableMeta.FILE_PARENT);\r
-        mProjectionMap.put(ProviderTableMeta.FILE_PATH,\r
-                ProviderTableMeta.FILE_PATH);\r
-        mProjectionMap.put(ProviderTableMeta.FILE_NAME,\r
-                ProviderTableMeta.FILE_NAME);\r
-        mProjectionMap.put(ProviderTableMeta.FILE_CREATION,\r
-                ProviderTableMeta.FILE_CREATION);\r
-        mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED,\r
-                ProviderTableMeta.FILE_MODIFIED);\r
-        mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,\r
-                ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA);\r
-        mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH,\r
-                ProviderTableMeta.FILE_CONTENT_LENGTH);\r
-        mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE,\r
-                ProviderTableMeta.FILE_CONTENT_TYPE);\r
-        mProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH,\r
-                ProviderTableMeta.FILE_STORAGE_PATH);\r
-        mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE,\r
-                ProviderTableMeta.FILE_LAST_SYNC_DATE);\r
-        mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA,\r
-                ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA);\r
-        mProjectionMap.put(ProviderTableMeta.FILE_KEEP_IN_SYNC,\r
-                ProviderTableMeta.FILE_KEEP_IN_SYNC);\r
-        mProjectionMap.put(ProviderTableMeta.FILE_ACCOUNT_OWNER,\r
-                ProviderTableMeta.FILE_ACCOUNT_OWNER);\r
-    }\r
-\r
-    private static final int SINGLE_FILE = 1;\r
-    private static final int DIRECTORY = 2;\r
-    private static final int ROOT_DIRECTORY = 3;\r
-    private static final UriMatcher mUriMatcher;\r
-    static {\r
-        mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);\r
-        mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "/", ROOT_DIRECTORY);\r
-        mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE);\r
-        mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE);\r
-        mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY);\r
-    }\r
-\r
-    @Override\r
-    public int delete(Uri uri, String where, String[] whereArgs) {\r
-        SQLiteDatabase db = mDbHelper.getWritableDatabase();\r
-        int count = 0;\r
-        switch (mUriMatcher.match(uri)) {\r
-        case SINGLE_FILE:\r
-            count = db.delete(ProviderTableMeta.DB_NAME,\r
-                    ProviderTableMeta._ID\r
-                            + "="\r
-                            + uri.getPathSegments().get(1)\r
-                            + (!TextUtils.isEmpty(where) ? " AND (" + where\r
-                                    + ")" : ""), whereArgs);\r
-            break;\r
-        case ROOT_DIRECTORY:\r
-            count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs);\r
-            break;\r
-        default:\r
-            throw new IllegalArgumentException("Unknown uri: " + uri.toString());\r
-        }\r
-        getContext().getContentResolver().notifyChange(uri, null);\r
-        return count;\r
-    }\r
-\r
-    @Override\r
-    public String getType(Uri uri) {\r
-        switch (mUriMatcher.match(uri)) {\r
-        case ROOT_DIRECTORY:\r
-            return ProviderTableMeta.CONTENT_TYPE;\r
-        case SINGLE_FILE:\r
-            return ProviderTableMeta.CONTENT_TYPE_ITEM;\r
-        default:\r
-            throw new IllegalArgumentException("Unknown Uri id."\r
-                    + uri.toString());\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public Uri insert(Uri uri, ContentValues values) {\r
-        if (mUriMatcher.match(uri) != SINGLE_FILE &&\r
-            mUriMatcher.match(uri) != ROOT_DIRECTORY) {\r
-            \r
-            throw new IllegalArgumentException("Unknown uri id: " + uri);\r
-        }\r
-\r
-        SQLiteDatabase db = mDbHelper.getWritableDatabase();\r
-        long rowId = db.insert(ProviderTableMeta.DB_NAME, null, values);\r
-        if (rowId > 0) {\r
-            Uri insertedFileUri = ContentUris.withAppendedId(\r
-                    ProviderTableMeta.CONTENT_URI_FILE, rowId);\r
-            getContext().getContentResolver().notifyChange(insertedFileUri,\r
-                    null);\r
-            return insertedFileUri;\r
-        }\r
-        throw new SQLException("ERROR " + uri);\r
-    }\r
-\r
-    @Override\r
-    public boolean onCreate() {\r
-        mDbHelper = new DataBaseHelper(getContext());\r
-        return true;\r
-    }\r
-\r
-    @Override\r
-    public Cursor query(Uri uri, String[] projection, String selection,\r
-            String[] selectionArgs, String sortOrder) {\r
-        SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder();\r
-\r
-        sqlQuery.setTables(ProviderTableMeta.DB_NAME);\r
-        sqlQuery.setProjectionMap(mProjectionMap);\r
-\r
-        switch (mUriMatcher.match(uri)) {\r
-        case ROOT_DIRECTORY:\r
-            break;\r
-        case DIRECTORY:\r
-            sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="\r
-                    + uri.getPathSegments().get(1));\r
-            break;\r
-        case SINGLE_FILE:\r
-            if (uri.getPathSegments().size() > 1) {\r
-                sqlQuery.appendWhere(ProviderTableMeta._ID + "="\r
-                        + uri.getPathSegments().get(1));\r
-            }\r
-            break;\r
-        default:\r
-            throw new IllegalArgumentException("Unknown uri id: " + uri);\r
-        }\r
-\r
-        String order;\r
-        if (TextUtils.isEmpty(sortOrder)) {\r
-            order = ProviderTableMeta.DEFAULT_SORT_ORDER;\r
-        } else {\r
-            order = sortOrder;\r
-        }\r
-\r
-        SQLiteDatabase db = mDbHelper.getReadableDatabase();\r
-        Cursor c = sqlQuery.query(db, projection, selection, selectionArgs,\r
-                null, null, order);\r
-\r
-        c.setNotificationUri(getContext().getContentResolver(), uri);\r
-\r
-        return c;\r
-    }\r
-\r
-    @Override\r
-    public int update(Uri uri, ContentValues values, String selection,\r
-            String[] selectionArgs) {\r
-        return mDbHelper.getWritableDatabase().update(\r
-                ProviderTableMeta.DB_NAME, values, selection, selectionArgs);\r
-    }\r
-\r
-    class DataBaseHelper extends SQLiteOpenHelper {\r
-\r
-        public DataBaseHelper(Context context) {\r
-            super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION);\r
-\r
-        }\r
-\r
-        @Override\r
-        public void onCreate(SQLiteDatabase db) {\r
-            // files table\r
-            Log.i("SQL", "Entering in onCreate");\r
-            db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "("\r
-                    + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "\r
-                    + ProviderTableMeta.FILE_NAME + " TEXT, "\r
-                    + ProviderTableMeta.FILE_PATH + " TEXT, "\r
-                    + ProviderTableMeta.FILE_PARENT + " INTEGER, "\r
-                    + ProviderTableMeta.FILE_CREATION + " INTEGER, "\r
-                    + ProviderTableMeta.FILE_MODIFIED + " INTEGER, "\r
-                    + ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, "\r
-                    + ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, "\r
-                    + ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, "\r
-                    + ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT, "\r
-                    + ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, "\r
-                    + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER, "\r
-                    + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, "\r
-                    + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER );"\r
-                    );\r
-        }\r
-\r
-        @Override\r
-        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\r
-            Log.i("SQL", "Entering in onUpgrade");\r
-            boolean upgraded = false; \r
-            if (oldVersion == 1 && newVersion >= 2) {\r
-                Log.i("SQL", "Entering in the #1 ADD in onUpgrade");\r
-                db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +\r
-                           " ADD COLUMN " + ProviderTableMeta.FILE_KEEP_IN_SYNC  + " INTEGER " +\r
-                           " DEFAULT 0");\r
-                upgraded = true;\r
-            }\r
-            if (oldVersion < 3 && newVersion >= 3) {\r
-                Log.i("SQL", "Entering in the #2 ADD in onUpgrade");\r
-                db.beginTransaction();\r
-                try {\r
-                    db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +\r
-                               " ADD COLUMN " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA  + " INTEGER " +\r
-                               " DEFAULT 0");\r
-                    \r
-                    // assume there are not local changes pending to upload\r
-                    db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + \r
-                            " SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = " + System.currentTimeMillis() + \r
-                            " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");\r
-                 \r
-                    upgraded = true;\r
-                    db.setTransactionSuccessful();\r
-                } finally {\r
-                    db.endTransaction();\r
-                }\r
-            }\r
-            if (oldVersion < 4 && newVersion >= 4) {\r
-                Log.i("SQL", "Entering in the #3 ADD in onUpgrade");\r
-                db.beginTransaction();\r
-                try {\r
-                    db .execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +\r
-                           " ADD COLUMN " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA  + " INTEGER " +\r
-                           " DEFAULT 0");\r
-                \r
-                    db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + \r
-                           " SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " + ProviderTableMeta.FILE_MODIFIED + \r
-                           " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");\r
-                \r
-                    upgraded = true;\r
-                    db.setTransactionSuccessful();\r
-                } finally {\r
-                    db.endTransaction();\r
-                }\r
-            }\r
-            if (!upgraded)\r
-                Log.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);\r
-        }\r
-\r
-    }\r
-\r
-}\r
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License 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.providers;
+
+import java.util.HashMap;
+
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.db.ProviderMeta;
+import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
+
+
+import android.content.ContentProvider;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.net.Uri;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * The ContentProvider for the ownCloud App.
+ * 
+ * @author Bartek Przybylski
+ * 
+ */
+public class FileContentProvider extends ContentProvider {
+
+    private DataBaseHelper mDbHelper;
+
+    private static HashMap<String, String> mProjectionMap;
+    static {
+        mProjectionMap = new HashMap<String, String>();
+        mProjectionMap.put(ProviderTableMeta._ID, ProviderTableMeta._ID);
+        mProjectionMap.put(ProviderTableMeta.FILE_PARENT,
+                ProviderTableMeta.FILE_PARENT);
+        mProjectionMap.put(ProviderTableMeta.FILE_PATH,
+                ProviderTableMeta.FILE_PATH);
+        mProjectionMap.put(ProviderTableMeta.FILE_NAME,
+                ProviderTableMeta.FILE_NAME);
+        mProjectionMap.put(ProviderTableMeta.FILE_CREATION,
+                ProviderTableMeta.FILE_CREATION);
+        mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED,
+                ProviderTableMeta.FILE_MODIFIED);
+        mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
+                ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA);
+        mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH,
+                ProviderTableMeta.FILE_CONTENT_LENGTH);
+        mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE,
+                ProviderTableMeta.FILE_CONTENT_TYPE);
+        mProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH,
+                ProviderTableMeta.FILE_STORAGE_PATH);
+        mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE,
+                ProviderTableMeta.FILE_LAST_SYNC_DATE);
+        mProjectionMap.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA,
+                ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA);
+        mProjectionMap.put(ProviderTableMeta.FILE_KEEP_IN_SYNC,
+                ProviderTableMeta.FILE_KEEP_IN_SYNC);
+        mProjectionMap.put(ProviderTableMeta.FILE_ACCOUNT_OWNER,
+                ProviderTableMeta.FILE_ACCOUNT_OWNER);
+    }
+
+    private static final int SINGLE_FILE = 1;
+    private static final int DIRECTORY = 2;
+    private static final int ROOT_DIRECTORY = 3;
+    private static final UriMatcher mUriMatcher;
+    static {
+        mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+        mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "/", ROOT_DIRECTORY);
+        mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE);
+        mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE);
+        mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY);
+    }
+
+    @Override
+    public int delete(Uri uri, String where, String[] whereArgs) {
+        SQLiteDatabase db = mDbHelper.getWritableDatabase();
+        int count = 0;
+        switch (mUriMatcher.match(uri)) {
+        case SINGLE_FILE:
+            count = db.delete(ProviderTableMeta.DB_NAME,
+                    ProviderTableMeta._ID
+                            + "="
+                            + uri.getPathSegments().get(1)
+                            + (!TextUtils.isEmpty(where) ? " AND (" + where
+                                    + ")" : ""), whereArgs);
+            break;
+        case ROOT_DIRECTORY:
+            count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs);
+            break;
+        default:
+            throw new IllegalArgumentException("Unknown uri: " + uri.toString());
+        }
+        getContext().getContentResolver().notifyChange(uri, null);
+        return count;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        switch (mUriMatcher.match(uri)) {
+        case ROOT_DIRECTORY:
+            return ProviderTableMeta.CONTENT_TYPE;
+        case SINGLE_FILE:
+            return ProviderTableMeta.CONTENT_TYPE_ITEM;
+        default:
+            throw new IllegalArgumentException("Unknown Uri id."
+                    + uri.toString());
+        }
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        if (mUriMatcher.match(uri) != SINGLE_FILE &&
+            mUriMatcher.match(uri) != ROOT_DIRECTORY) {
+            
+            throw new IllegalArgumentException("Unknown uri id: " + uri);
+        }
+
+        SQLiteDatabase db = mDbHelper.getWritableDatabase();
+        long rowId = db.insert(ProviderTableMeta.DB_NAME, null, values);
+        if (rowId > 0) {
+            Uri insertedFileUri = ContentUris.withAppendedId(
+                    ProviderTableMeta.CONTENT_URI_FILE, rowId);
+            getContext().getContentResolver().notifyChange(insertedFileUri,
+                    null);
+            return insertedFileUri;
+        }
+        throw new SQLException("ERROR " + uri);
+    }
+
+    @Override
+    public boolean onCreate() {
+        mDbHelper = new DataBaseHelper(getContext());
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection,
+            String[] selectionArgs, String sortOrder) {
+        SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder();
+
+        sqlQuery.setTables(ProviderTableMeta.DB_NAME);
+        sqlQuery.setProjectionMap(mProjectionMap);
+
+        switch (mUriMatcher.match(uri)) {
+        case ROOT_DIRECTORY:
+            break;
+        case DIRECTORY:
+            sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="
+                    + uri.getPathSegments().get(1));
+            break;
+        case SINGLE_FILE:
+            if (uri.getPathSegments().size() > 1) {
+                sqlQuery.appendWhere(ProviderTableMeta._ID + "="
+                        + uri.getPathSegments().get(1));
+            }
+            break;
+        default:
+            throw new IllegalArgumentException("Unknown uri id: " + uri);
+        }
+
+        String order;
+        if (TextUtils.isEmpty(sortOrder)) {
+            order = ProviderTableMeta.DEFAULT_SORT_ORDER;
+        } else {
+            order = sortOrder;
+        }
+
+        SQLiteDatabase db = mDbHelper.getReadableDatabase();
+        Cursor c = sqlQuery.query(db, projection, selection, selectionArgs,
+                null, null, order);
+
+        c.setNotificationUri(getContext().getContentResolver(), uri);
+
+        return c;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection,
+            String[] selectionArgs) {
+        return mDbHelper.getWritableDatabase().update(
+                ProviderTableMeta.DB_NAME, values, selection, selectionArgs);
+    }
+
+    class DataBaseHelper extends SQLiteOpenHelper {
+
+        public DataBaseHelper(Context context) {
+            super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION);
+
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            // files table
+            Log_OC.i("SQL", "Entering in onCreate");
+            db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "("
+                    + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
+                    + ProviderTableMeta.FILE_NAME + " TEXT, "
+                    + ProviderTableMeta.FILE_PATH + " TEXT, "
+                    + ProviderTableMeta.FILE_PARENT + " INTEGER, "
+                    + ProviderTableMeta.FILE_CREATION + " INTEGER, "
+                    + ProviderTableMeta.FILE_MODIFIED + " INTEGER, "
+                    + ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, "
+                    + ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, "
+                    + ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, "
+                    + ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT, "
+                    + ProviderTableMeta.FILE_LAST_SYNC_DATE + " INTEGER, "
+                    + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER, "
+                    + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " INTEGER, "
+                    + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " INTEGER );"
+                    );
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            Log_OC.i("SQL", "Entering in onUpgrade");
+            boolean upgraded = false; 
+            if (oldVersion == 1 && newVersion >= 2) {
+                Log_OC.i("SQL", "Entering in the #1 ADD in onUpgrade");
+                db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +
+                           " ADD COLUMN " + ProviderTableMeta.FILE_KEEP_IN_SYNC  + " INTEGER " +
+                           " DEFAULT 0");
+                upgraded = true;
+            }
+            if (oldVersion < 3 && newVersion >= 3) {
+                Log_OC.i("SQL", "Entering in the #2 ADD in onUpgrade");
+                db.beginTransaction();
+                try {
+                    db.execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +
+                               " ADD COLUMN " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA  + " INTEGER " +
+                               " DEFAULT 0");
+                    
+                    // assume there are not local changes pending to upload
+                    db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + 
+                            " SET " + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + " = " + System.currentTimeMillis() + 
+                            " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");
+                 
+                    upgraded = true;
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                }
+            }
+            if (oldVersion < 4 && newVersion >= 4) {
+                Log_OC.i("SQL", "Entering in the #3 ADD in onUpgrade");
+                db.beginTransaction();
+                try {
+                    db .execSQL("ALTER TABLE " + ProviderTableMeta.DB_NAME +
+                           " ADD COLUMN " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA  + " INTEGER " +
+                           " DEFAULT 0");
+                
+                    db.execSQL("UPDATE " + ProviderTableMeta.DB_NAME + 
+                           " SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " + ProviderTableMeta.FILE_MODIFIED + 
+                           " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL");
+                
+                    upgraded = true;
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                }
+            }
+            if (!upgraded)
+                Log_OC.i("SQL", "OUT of the ADD in onUpgrade; oldVersion == " + oldVersion + ", newVersion == " + newVersion);
+        }
+
+    }
+
+}
index 6da3e81..3dc80d9 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.syncadapter;\r
-\r
-import java.io.IOException;\r
-import java.net.UnknownHostException;\r
-import java.util.ArrayList;\r
-import java.util.HashMap;\r
-import java.util.List;\r
-import java.util.Map;\r
-\r
-import org.apache.jackrabbit.webdav.DavException;\r
-\r
-import com.owncloud.android.R;\r
-import com.owncloud.android.datamodel.DataStorageManager;\r
-import com.owncloud.android.datamodel.FileDataStorageManager;\r
-import com.owncloud.android.datamodel.OCFile;\r
-import com.owncloud.android.operations.RemoteOperationResult;\r
-import com.owncloud.android.operations.SynchronizeFolderOperation;\r
-import com.owncloud.android.operations.UpdateOCVersionOperation;\r
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;\r
-import com.owncloud.android.ui.activity.ErrorsWhileCopyingHandlerActivity;\r
-import android.accounts.Account;\r
-import android.app.Notification;\r
-import android.app.NotificationManager;\r
-import android.app.PendingIntent;\r
-import android.content.ContentProviderClient;\r
-import android.content.ContentResolver;\r
-import android.content.Context;\r
-import android.content.Intent;\r
-import android.content.SyncResult;\r
-import android.os.Bundle;\r
-import android.util.Log;\r
-\r
-/**\r
- * SyncAdapter implementation for syncing sample SyncAdapter contacts to the\r
- * platform ContactOperations provider.\r
- * \r
- * @author Bartek Przybylski\r
- */\r
-public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {\r
-\r
-    private final static String TAG = "FileSyncAdapter";\r
-\r
-    /** \r
-     * Maximum number of failed folder synchronizations that are supported before finishing the synchronization operation\r
-     */\r
-    private static final int MAX_FAILED_RESULTS = 3; \r
-    \r
-    private long mCurrentSyncTime;\r
-    private boolean mCancellation;\r
-    private boolean mIsManualSync;\r
-    private int mFailedResultsCounter;    \r
-    private RemoteOperationResult mLastFailedResult;\r
-    private SyncResult mSyncResult;\r
-    private int mConflictsFound;\r
-    private int mFailsInFavouritesFound;\r
-    private Map<String, String> mForgottenLocalFiles;\r
-\r
-    \r
-    public FileSyncAdapter(Context context, boolean autoInitialize) {\r
-        super(context, autoInitialize);\r
-    }\r
-\r
-    /**\r
-     * {@inheritDoc}\r
-     */\r
-    @Override\r
-    public synchronized void onPerformSync(Account account, Bundle extras,\r
-            String authority, ContentProviderClient provider,\r
-            SyncResult syncResult) {\r
-\r
-        mCancellation = false;\r
-        mIsManualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);\r
-        mFailedResultsCounter = 0;\r
-        mLastFailedResult = null;\r
-        mConflictsFound = 0;\r
-        mFailsInFavouritesFound = 0;\r
-        mForgottenLocalFiles = new HashMap<String, String>();\r
-        mSyncResult = syncResult;\r
-        mSyncResult.fullSyncRequested = false;\r
-        mSyncResult.delayUntil = 60*60*24; // sync after 24h\r
-\r
-        this.setAccount(account);\r
-        this.setContentProvider(provider);\r
-        this.setStorageManager(new FileDataStorageManager(account, getContentProvider()));\r
-        try {\r
-            this.initClientForCurrentAccount();\r
-        } catch (UnknownHostException e) {\r
-            /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again\r
-            mSyncResult.tooManyRetries = true;\r
-            notifyFailedSynchronization();\r
-            return;\r
-        }\r
-        \r
-        Log.d(TAG, "Synchronization of ownCloud account " + account.name + " starting");\r
-        sendStickyBroadcast(true, null, null);  // message to signal the start of the synchronization to the UI\r
-        \r
-        try {\r
-            updateOCVersion();\r
-            mCurrentSyncTime = System.currentTimeMillis();\r
-            if (!mCancellation) {\r
-                fetchData(OCFile.PATH_SEPARATOR, DataStorageManager.ROOT_PARENT_ID);\r
-                \r
-            } else {\r
-                Log.d(TAG, "Leaving synchronization before any remote request due to cancellation was requested");\r
-            }\r
-            \r
-            \r
-        } finally {\r
-            // it's important making this although very unexpected errors occur; that's the reason for the finally\r
-            \r
-            if (mFailedResultsCounter > 0 && mIsManualSync) {\r
-                /// don't let the system synchronization manager retries MANUAL synchronizations\r
-                //      (be careful: "MANUAL" currently includes the synchronization requested when a new account is created and when the user changes the current account)\r
-                mSyncResult.tooManyRetries = true;\r
-                \r
-                /// notify the user about the failure of MANUAL synchronization\r
-                notifyFailedSynchronization();\r
-                \r
-            }\r
-            if (mConflictsFound > 0 || mFailsInFavouritesFound > 0) {\r
-                notifyFailsInFavourites();\r
-            }\r
-            if (mForgottenLocalFiles.size() > 0) {\r
-                notifyForgottenLocalFiles();\r
-                \r
-            }\r
-            sendStickyBroadcast(false, null, mLastFailedResult);        // message to signal the end to the UI\r
-        }\r
-        \r
-    }\r
-\r
-    \r
-    /**\r
-     * Called by system SyncManager when a synchronization is required to be cancelled.\r
-     * \r
-     * Sets the mCancellation flag to 'true'. THe synchronization will be stopped when before a new folder is fetched. Data of the last folder\r
-     * fetched will be still saved in the database. See onPerformSync implementation.\r
-     */\r
-    @Override\r
-    public void onSyncCanceled() {\r
-        Log.d(TAG, "Synchronization of " + getAccount().name + " has been requested to cancel");\r
-        mCancellation = true;\r
-        super.onSyncCanceled();\r
-    }\r
-    \r
-    \r
-    /**\r
-     * Updates the locally stored version value of the ownCloud server\r
-     */\r
-    private void updateOCVersion() {\r
-        UpdateOCVersionOperation update = new UpdateOCVersionOperation(getAccount(), getContext());\r
-        RemoteOperationResult result = update.execute(getClient());\r
-        if (!result.isSuccess()) {\r
-            mLastFailedResult = result; \r
-        }\r
-    }\r
-\r
-    \r
-    \r
-    /**\r
-     * Synchronize the properties of files and folders contained in a remote folder given by remotePath.\r
-     * \r
-     * @param remotePath        Remote path to the folder to synchronize.\r
-     * @param parentId          Database Id of the folder to synchronize.\r
-     */\r
-    private void fetchData(String remotePath, long parentId) {\r
-        \r
-        if (mFailedResultsCounter > MAX_FAILED_RESULTS || isFinisher(mLastFailedResult))\r
-            return;\r
-        \r
-        // perform folder synchronization\r
-        SynchronizeFolderOperation synchFolderOp = new SynchronizeFolderOperation(  remotePath, \r
-                                                                                    mCurrentSyncTime, \r
-                                                                                    parentId, \r
-                                                                                    getStorageManager(), \r
-                                                                                    getAccount(), \r
-                                                                                    getContext()\r
-                                                                                  );\r
-        RemoteOperationResult result = synchFolderOp.execute(getClient());\r
-        \r
-        \r
-        // synchronized folder -> notice to UI - ALWAYS, although !result.isSuccess\r
-        sendStickyBroadcast(true, remotePath, null);\r
-        \r
-        if (result.isSuccess() || result.getCode() == ResultCode.SYNC_CONFLICT) {\r
-            \r
-            if (result.getCode() == ResultCode.SYNC_CONFLICT) {\r
-                mConflictsFound += synchFolderOp.getConflictsFound();\r
-                mFailsInFavouritesFound += synchFolderOp.getFailsInFavouritesFound();\r
-            }\r
-            if (synchFolderOp.getForgottenLocalFiles().size() > 0) {\r
-                mForgottenLocalFiles.putAll(synchFolderOp.getForgottenLocalFiles());\r
-            }\r
-            // synchronize children folders \r
-            List<OCFile> children = synchFolderOp.getChildren();\r
-            fetchChildren(children);    // beware of the 'hidden' recursion here!\r
-            \r
-        } else {\r
-            if (result.getCode() == RemoteOperationResult.ResultCode.UNAUTHORIZED) {\r
-                mSyncResult.stats.numAuthExceptions++;\r
-                \r
-            } else if (result.getException() instanceof DavException) {\r
-                mSyncResult.stats.numParseExceptions++;\r
-                \r
-            } else if (result.getException() instanceof IOException) { \r
-                mSyncResult.stats.numIoExceptions++;\r
-            }\r
-            mFailedResultsCounter++;\r
-            mLastFailedResult = result;\r
-        }\r
-            \r
-    }\r
-\r
-    /**\r
-     * Checks if a failed result should terminate the synchronization process immediately, according to\r
-     * OUR OWN POLICY\r
-     * \r
-     * @param   failedResult        Remote operation result to check.\r
-     * @return                      'True' if the result should immediately finish the synchronization\r
-     */\r
-    private boolean isFinisher(RemoteOperationResult failedResult) {\r
-        if  (failedResult != null) {\r
-            RemoteOperationResult.ResultCode code = failedResult.getCode();\r
-            return (code.equals(RemoteOperationResult.ResultCode.SSL_ERROR) ||\r
-                    code.equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) ||\r
-                    code.equals(RemoteOperationResult.ResultCode.BAD_OC_VERSION) ||\r
-                    code.equals(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED));\r
-        }\r
-        return false;\r
-    }\r
-\r
-    /**\r
-     * Synchronize data of folders in the list of received files\r
-     * \r
-     * @param files         Files to recursively fetch \r
-     */\r
-    private void fetchChildren(List<OCFile> files) {\r
-        int i;\r
-        for (i=0; i < files.size() && !mCancellation; i++) {\r
-            OCFile newFile = files.get(i);\r
-            if (newFile.isDirectory()) {\r
-                fetchData(newFile.getRemotePath(), newFile.getFileId());\r
-            }\r
-        }\r
-        if (mCancellation && i <files.size()) Log.d(TAG, "Leaving synchronization before synchronizing " + files.get(i).getRemotePath() + " because cancelation request");\r
-    }\r
-\r
-    \r
-    /**\r
-     * Sends a message to any application component interested in the progress of the synchronization.\r
-     * \r
-     * @param inProgress        'True' when the synchronization progress is not finished.\r
-     * @param dirRemotePath     Remote path of a folder that was just synchronized (with or without success)\r
-     */\r
-    private void sendStickyBroadcast(boolean inProgress, String dirRemotePath, RemoteOperationResult result) {\r
-        Intent i = new Intent(FileSyncService.SYNC_MESSAGE);\r
-        i.putExtra(FileSyncService.IN_PROGRESS, inProgress);\r
-        i.putExtra(FileSyncService.ACCOUNT_NAME, getAccount().name);\r
-        if (dirRemotePath != null) {\r
-            i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath);\r
-        }\r
-        if (result != null) {\r
-            i.putExtra(FileSyncService.SYNC_RESULT, result);\r
-        }\r
-        getContext().sendStickyBroadcast(i);\r
-    }\r
-\r
-    \r
-    \r
-    /**\r
-     * Notifies the user about a failed synchronization through the status notification bar \r
-     */\r
-    private void notifyFailedSynchronization() {\r
-        Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_ticker), System.currentTimeMillis());\r
-        notification.flags |= Notification.FLAG_AUTO_CANCEL;\r
-        // TODO put something smart in the contentIntent below\r
-        notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);\r
-        notification.setLatestEventInfo(getContext().getApplicationContext(), \r
-                                        getContext().getString(R.string.sync_fail_ticker), \r
-                                        String.format(getContext().getString(R.string.sync_fail_content), getAccount().name), \r
-                                        notification.contentIntent);\r
-        ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_ticker, notification);\r
-    }\r
-\r
-\r
-    /**\r
-     * Notifies the user about conflicts and strange fails when trying to synchronize the contents of kept-in-sync files.\r
-     * \r
-     * By now, we won't consider a failed synchronization.\r
-     */\r
-    private void notifyFailsInFavourites() {\r
-        if (mFailedResultsCounter > 0) {\r
-            Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_in_favourites_ticker), System.currentTimeMillis());\r
-            notification.flags |= Notification.FLAG_AUTO_CANCEL;\r
-            // TODO put something smart in the contentIntent below\r
-            notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);\r
-            notification.setLatestEventInfo(getContext().getApplicationContext(), \r
-                                            getContext().getString(R.string.sync_fail_in_favourites_ticker), \r
-                                            String.format(getContext().getString(R.string.sync_fail_in_favourites_content), mFailedResultsCounter + mConflictsFound, mConflictsFound), \r
-                                            notification.contentIntent);\r
-            ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_in_favourites_ticker, notification);\r
-            \r
-        } else {\r
-            Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_conflicts_in_favourites_ticker), System.currentTimeMillis());\r
-            notification.flags |= Notification.FLAG_AUTO_CANCEL;\r
-            // TODO put something smart in the contentIntent below\r
-            notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);\r
-            notification.setLatestEventInfo(getContext().getApplicationContext(), \r
-                                            getContext().getString(R.string.sync_conflicts_in_favourites_ticker), \r
-                                            String.format(getContext().getString(R.string.sync_conflicts_in_favourites_content), mConflictsFound), \r
-                                            notification.contentIntent);\r
-            ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_conflicts_in_favourites_ticker, notification);\r
-        } \r
-    }\r
-\r
-    \r
-    /**\r
-     * Notifies the user about local copies of files out of the ownCloud local directory that were 'forgotten' because \r
-     * copying them inside the ownCloud local directory was not possible.\r
-     * \r
-     * We don't want links to files out of the ownCloud local directory (foreign files) anymore. It's easy to have \r
-     * synchronization problems if a local file is linked to more than one remote file.\r
-     * \r
-     * We won't consider a synchronization as failed when foreign files can not be copied to the ownCloud local directory.\r
-     */\r
-    private void notifyForgottenLocalFiles() {\r
-        Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_foreign_files_forgotten_ticker), System.currentTimeMillis());\r
-        notification.flags |= Notification.FLAG_AUTO_CANCEL;\r
-\r
-        /// includes a pending intent in the notification showing a more detailed explanation\r
-        Intent explanationIntent = new Intent(getContext(), ErrorsWhileCopyingHandlerActivity.class);\r
-        explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_ACCOUNT, getAccount());\r
-        ArrayList<String> remotePaths = new ArrayList<String>();\r
-        ArrayList<String> localPaths = new ArrayList<String>();\r
-        remotePaths.addAll(mForgottenLocalFiles.keySet());\r
-        localPaths.addAll(mForgottenLocalFiles.values());\r
-        explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_LOCAL_PATHS, localPaths);\r
-        explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_REMOTE_PATHS, remotePaths);  \r
-        explanationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
-        \r
-        notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), explanationIntent, 0);\r
-        notification.setLatestEventInfo(getContext().getApplicationContext(), \r
-                                        getContext().getString(R.string.sync_foreign_files_forgotten_ticker), \r
-                                        String.format(getContext().getString(R.string.sync_foreign_files_forgotten_content), mForgottenLocalFiles.size(), getContext().getString(R.string.app_name)), \r
-                                        notification.contentIntent);\r
-        ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_foreign_files_forgotten_ticker, notification);\r
-        \r
-    }\r
-    \r
-    \r
-}\r
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License 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.syncadapter;
+
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.jackrabbit.webdav.DavException;
+
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.DataStorageManager;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.operations.RemoteOperationResult;
+import com.owncloud.android.operations.SynchronizeFolderOperation;
+import com.owncloud.android.operations.UpdateOCVersionOperation;
+import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.ui.activity.ErrorsWhileCopyingHandlerActivity;
+import android.accounts.Account;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * SyncAdapter implementation for syncing sample SyncAdapter contacts to the
+ * platform ContactOperations provider.
+ * 
+ * @author Bartek Przybylski
+ */
+public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
+
+    private final static String TAG = "FileSyncAdapter";
+
+    /** 
+     * Maximum number of failed folder synchronizations that are supported before finishing the synchronization operation
+     */
+    private static final int MAX_FAILED_RESULTS = 3; 
+    
+    private long mCurrentSyncTime;
+    private boolean mCancellation;
+    private boolean mIsManualSync;
+    private int mFailedResultsCounter;    
+    private RemoteOperationResult mLastFailedResult;
+    private SyncResult mSyncResult;
+    private int mConflictsFound;
+    private int mFailsInFavouritesFound;
+    private Map<String, String> mForgottenLocalFiles;
+
+    
+    public FileSyncAdapter(Context context, boolean autoInitialize) {
+        super(context, autoInitialize);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public synchronized void onPerformSync(Account account, Bundle extras,
+            String authority, ContentProviderClient provider,
+            SyncResult syncResult) {
+
+        mCancellation = false;
+        mIsManualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
+        mFailedResultsCounter = 0;
+        mLastFailedResult = null;
+        mConflictsFound = 0;
+        mFailsInFavouritesFound = 0;
+        mForgottenLocalFiles = new HashMap<String, String>();
+        mSyncResult = syncResult;
+        mSyncResult.fullSyncRequested = false;
+        mSyncResult.delayUntil = 60*60*24; // sync after 24h
+
+        this.setAccount(account);
+        this.setContentProvider(provider);
+        this.setStorageManager(new FileDataStorageManager(account, getContentProvider()));
+        try {
+            this.initClientForCurrentAccount();
+        } catch (UnknownHostException e) {
+            /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again
+            mSyncResult.tooManyRetries = true;
+            notifyFailedSynchronization();
+            return;
+        }
+        
+        Log_OC.d(TAG, "Synchronization of ownCloud account " + account.name + " starting");
+        sendStickyBroadcast(true, null, null);  // message to signal the start of the synchronization to the UI
+        
+        try {
+            updateOCVersion();
+            mCurrentSyncTime = System.currentTimeMillis();
+            if (!mCancellation) {
+                fetchData(OCFile.PATH_SEPARATOR, DataStorageManager.ROOT_PARENT_ID);
+                
+            } else {
+                Log_OC.d(TAG, "Leaving synchronization before any remote request due to cancellation was requested");
+            }
+            
+            
+        } finally {
+            // it's important making this although very unexpected errors occur; that's the reason for the finally
+            
+            if (mFailedResultsCounter > 0 && mIsManualSync) {
+                /// don't let the system synchronization manager retries MANUAL synchronizations
+                //      (be careful: "MANUAL" currently includes the synchronization requested when a new account is created and when the user changes the current account)
+                mSyncResult.tooManyRetries = true;
+                
+                /// notify the user about the failure of MANUAL synchronization
+                notifyFailedSynchronization();
+                
+            }
+            if (mConflictsFound > 0 || mFailsInFavouritesFound > 0) {
+                notifyFailsInFavourites();
+            }
+            if (mForgottenLocalFiles.size() > 0) {
+                notifyForgottenLocalFiles();
+                
+            }
+            sendStickyBroadcast(false, null, mLastFailedResult);        // message to signal the end to the UI
+        }
+        
+    }
+
+    
+    /**
+     * Called by system SyncManager when a synchronization is required to be cancelled.
+     * 
+     * Sets the mCancellation flag to 'true'. THe synchronization will be stopped when before a new folder is fetched. Data of the last folder
+     * fetched will be still saved in the database. See onPerformSync implementation.
+     */
+    @Override
+    public void onSyncCanceled() {
+        Log_OC.d(TAG, "Synchronization of " + getAccount().name + " has been requested to cancel");
+        mCancellation = true;
+        super.onSyncCanceled();
+    }
+    
+    
+    /**
+     * Updates the locally stored version value of the ownCloud server
+     */
+    private void updateOCVersion() {
+        UpdateOCVersionOperation update = new UpdateOCVersionOperation(getAccount(), getContext());
+        RemoteOperationResult result = update.execute(getClient());
+        if (!result.isSuccess()) {
+            mLastFailedResult = result; 
+        }
+    }
+
+    
+    
+    /**
+     * Synchronize the properties of files and folders contained in a remote folder given by remotePath.
+     * 
+     * @param remotePath        Remote path to the folder to synchronize.
+     * @param parentId          Database Id of the folder to synchronize.
+     */
+    private void fetchData(String remotePath, long parentId) {
+        
+        if (mFailedResultsCounter > MAX_FAILED_RESULTS || isFinisher(mLastFailedResult))
+            return;
+        
+        // perform folder synchronization
+        SynchronizeFolderOperation synchFolderOp = new SynchronizeFolderOperation(  remotePath, 
+                                                                                    mCurrentSyncTime, 
+                                                                                    parentId, 
+                                                                                    getStorageManager(), 
+                                                                                    getAccount(), 
+                                                                                    getContext()
+                                                                                  );
+        RemoteOperationResult result = synchFolderOp.execute(getClient());
+        
+        
+        // synchronized folder -> notice to UI - ALWAYS, although !result.isSuccess
+        sendStickyBroadcast(true, remotePath, null);
+        
+        if (result.isSuccess() || result.getCode() == ResultCode.SYNC_CONFLICT) {
+            
+            if (result.getCode() == ResultCode.SYNC_CONFLICT) {
+                mConflictsFound += synchFolderOp.getConflictsFound();
+                mFailsInFavouritesFound += synchFolderOp.getFailsInFavouritesFound();
+            }
+            if (synchFolderOp.getForgottenLocalFiles().size() > 0) {
+                mForgottenLocalFiles.putAll(synchFolderOp.getForgottenLocalFiles());
+            }
+            // synchronize children folders 
+            List<OCFile> children = synchFolderOp.getChildren();
+            fetchChildren(children);    // beware of the 'hidden' recursion here!
+            
+        } else {
+            if (result.getCode() == RemoteOperationResult.ResultCode.UNAUTHORIZED) {
+                mSyncResult.stats.numAuthExceptions++;
+                
+            } else if (result.getException() instanceof DavException) {
+                mSyncResult.stats.numParseExceptions++;
+                
+            } else if (result.getException() instanceof IOException) { 
+                mSyncResult.stats.numIoExceptions++;
+            }
+            mFailedResultsCounter++;
+            mLastFailedResult = result;
+        }
+            
+    }
+
+    /**
+     * Checks if a failed result should terminate the synchronization process immediately, according to
+     * OUR OWN POLICY
+     * 
+     * @param   failedResult        Remote operation result to check.
+     * @return                      'True' if the result should immediately finish the synchronization
+     */
+    private boolean isFinisher(RemoteOperationResult failedResult) {
+        if  (failedResult != null) {
+            RemoteOperationResult.ResultCode code = failedResult.getCode();
+            return (code.equals(RemoteOperationResult.ResultCode.SSL_ERROR) ||
+                    code.equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) ||
+                    code.equals(RemoteOperationResult.ResultCode.BAD_OC_VERSION) ||
+                    code.equals(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED));
+        }
+        return false;
+    }
+
+    /**
+     * Synchronize data of folders in the list of received files
+     * 
+     * @param files         Files to recursively fetch 
+     */
+    private void fetchChildren(List<OCFile> files) {
+        int i;
+        for (i=0; i < files.size() && !mCancellation; i++) {
+            OCFile newFile = files.get(i);
+            if (newFile.isDirectory()) {
+                fetchData(newFile.getRemotePath(), newFile.getFileId());
+            }
+        }
+        if (mCancellation && i <files.size()) Log_OC.d(TAG, "Leaving synchronization before synchronizing " + files.get(i).getRemotePath() + " because cancelation request");
+    }
+
+    
+    /**
+     * Sends a message to any application component interested in the progress of the synchronization.
+     * 
+     * @param inProgress        'True' when the synchronization progress is not finished.
+     * @param dirRemotePath     Remote path of a folder that was just synchronized (with or without success)
+     */
+    private void sendStickyBroadcast(boolean inProgress, String dirRemotePath, RemoteOperationResult result) {
+        Intent i = new Intent(FileSyncService.SYNC_MESSAGE);
+        i.putExtra(FileSyncService.IN_PROGRESS, inProgress);
+        i.putExtra(FileSyncService.ACCOUNT_NAME, getAccount().name);
+        if (dirRemotePath != null) {
+            i.putExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH, dirRemotePath);
+        }
+        if (result != null) {
+            i.putExtra(FileSyncService.SYNC_RESULT, result);
+        }
+        getContext().sendStickyBroadcast(i);
+    }
+
+    
+    
+    /**
+     * Notifies the user about a failed synchronization through the status notification bar 
+     */
+    private void notifyFailedSynchronization() {
+        Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_ticker), System.currentTimeMillis());
+        notification.flags |= Notification.FLAG_AUTO_CANCEL;
+        // TODO put something smart in the contentIntent below
+        notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);
+        notification.setLatestEventInfo(getContext().getApplicationContext(), 
+                                        getContext().getString(R.string.sync_fail_ticker), 
+                                        String.format(getContext().getString(R.string.sync_fail_content), getAccount().name), 
+                                        notification.contentIntent);
+        ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_ticker, notification);
+    }
+
+
+    /**
+     * Notifies the user about conflicts and strange fails when trying to synchronize the contents of kept-in-sync files.
+     * 
+     * By now, we won't consider a failed synchronization.
+     */
+    private void notifyFailsInFavourites() {
+        if (mFailedResultsCounter > 0) {
+            Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_in_favourites_ticker), System.currentTimeMillis());
+            notification.flags |= Notification.FLAG_AUTO_CANCEL;
+            // TODO put something smart in the contentIntent below
+            notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);
+            notification.setLatestEventInfo(getContext().getApplicationContext(), 
+                                            getContext().getString(R.string.sync_fail_in_favourites_ticker), 
+                                            String.format(getContext().getString(R.string.sync_fail_in_favourites_content), mFailedResultsCounter + mConflictsFound, mConflictsFound), 
+                                            notification.contentIntent);
+            ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_in_favourites_ticker, notification);
+            
+        } else {
+            Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_conflicts_in_favourites_ticker), System.currentTimeMillis());
+            notification.flags |= Notification.FLAG_AUTO_CANCEL;
+            // TODO put something smart in the contentIntent below
+            notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);
+            notification.setLatestEventInfo(getContext().getApplicationContext(), 
+                                            getContext().getString(R.string.sync_conflicts_in_favourites_ticker), 
+                                            String.format(getContext().getString(R.string.sync_conflicts_in_favourites_content), mConflictsFound), 
+                                            notification.contentIntent);
+            ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_conflicts_in_favourites_ticker, notification);
+        } 
+    }
+
+    
+    /**
+     * Notifies the user about local copies of files out of the ownCloud local directory that were 'forgotten' because 
+     * copying them inside the ownCloud local directory was not possible.
+     * 
+     * We don't want links to files out of the ownCloud local directory (foreign files) anymore. It's easy to have 
+     * synchronization problems if a local file is linked to more than one remote file.
+     * 
+     * We won't consider a synchronization as failed when foreign files can not be copied to the ownCloud local directory.
+     */
+    private void notifyForgottenLocalFiles() {
+        Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_foreign_files_forgotten_ticker), System.currentTimeMillis());
+        notification.flags |= Notification.FLAG_AUTO_CANCEL;
+
+        /// includes a pending intent in the notification showing a more detailed explanation
+        Intent explanationIntent = new Intent(getContext(), ErrorsWhileCopyingHandlerActivity.class);
+        explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_ACCOUNT, getAccount());
+        ArrayList<String> remotePaths = new ArrayList<String>();
+        ArrayList<String> localPaths = new ArrayList<String>();
+        remotePaths.addAll(mForgottenLocalFiles.keySet());
+        localPaths.addAll(mForgottenLocalFiles.values());
+        explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_LOCAL_PATHS, localPaths);
+        explanationIntent.putExtra(ErrorsWhileCopyingHandlerActivity.EXTRA_REMOTE_PATHS, remotePaths);  
+        explanationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        
+        notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), explanationIntent, 0);
+        notification.setLatestEventInfo(getContext().getApplicationContext(), 
+                                        getContext().getString(R.string.sync_foreign_files_forgotten_ticker), 
+                                        String.format(getContext().getString(R.string.sync_foreign_files_forgotten_content), mForgottenLocalFiles.size(), getContext().getString(R.string.app_name)), 
+                                        notification.contentIntent);
+        ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_foreign_files_forgotten_ticker, notification);
+        
+    }
+    
+    
+}
index 31b59d4..2eca33a 100644 (file)
@@ -50,6 +50,7 @@ import com.actionbarsherlock.view.Menu;
 import com.actionbarsherlock.view.MenuInflater;
 import com.actionbarsherlock.view.MenuItem;
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.authenticator.AccountAuthenticator;
 
 import com.owncloud.android.R;
@@ -153,7 +154,7 @@ public class AccountSelectActivity extends SherlockListActivity implements
         try {
             map = (HashMap<String, String>) getListAdapter().getItem(index);
         } catch (ClassCastException e) {
-            Log.wtf(TAG, "getitem(index) from list adapter did not return hashmap, bailing out");
+            Log_OC.wtf(TAG, "getitem(index) from list adapter did not return hashmap, bailing out");
             return false;
         }
         
index d277040..2121329 100644 (file)
-/* ownCloud Android client application\r
- *   Copyright (C) 2012  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
- *\r
- *   This program is free software: you can redistribute it and/or modify\r
- *   it under the terms of the GNU General Public License as published by\r
- *   the Free Software Foundation, either version 2 of the License, or\r
- *   (at your option) any later version.\r
- *\r
- *   This program is distributed in the hope that it will be useful,\r
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- *   GNU General Public License for more details.\r
- *\r
- *   You should have received a copy of the GNU General Public License\r
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- */\r
-\r
-package com.owncloud.android.ui.activity;\r
-\r
-import java.net.MalformedURLException;\r
-import java.net.URL;\r
-\r
-import com.owncloud.android.AccountUtils;\r
-import com.owncloud.android.authenticator.AccountAuthenticator;\r
-import com.owncloud.android.authenticator.AuthenticationRunnable;\r
-import com.owncloud.android.authenticator.OnAuthenticationResultListener;\r
-import com.owncloud.android.authenticator.OnConnectCheckListener;\r
-import com.owncloud.android.ui.dialog.SslValidatorDialog;\r
-import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;\r
-import com.owncloud.android.network.OwnCloudClientUtils;\r
-import com.owncloud.android.operations.ConnectionCheckOperation;\r
-import com.owncloud.android.operations.OnRemoteOperationListener;\r
-import com.owncloud.android.operations.RemoteOperation;\r
-import com.owncloud.android.operations.RemoteOperationResult;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountAuthenticatorActivity;\r
-import android.accounts.AccountManager;\r
-import android.app.AlertDialog;\r
-import android.app.Dialog;\r
-import android.app.ProgressDialog;\r
-import android.content.ContentResolver;\r
-import android.content.DialogInterface;\r
-import android.content.Intent;\r
-import android.content.SharedPreferences;\r
-import android.net.Uri;\r
-import android.os.Bundle;\r
-import android.os.Handler;\r
-import android.preference.PreferenceManager;\r
-import android.text.InputType;\r
-import android.util.Log;\r
-import android.view.View;\r
-import android.view.View.OnClickListener;\r
-import android.view.View.OnFocusChangeListener;\r
-import android.view.Window;\r
-import android.widget.Button;\r
-import android.widget.EditText;\r
-import android.widget.ImageView;\r
-import android.widget.TextView;\r
-import com.owncloud.android.R;\r
-\r
-import eu.alefzero.webdav.WebdavClient;\r
-\r
-/**\r
- * This Activity is used to add an ownCloud account to the App\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class AuthenticatorActivity extends AccountAuthenticatorActivity\r
-        implements OnAuthenticationResultListener, OnConnectCheckListener, OnRemoteOperationListener, OnSslValidatorListener, \r
-        OnFocusChangeListener, OnClickListener {\r
-\r
-    private static final int DIALOG_LOGIN_PROGRESS = 0;\r
-    private static final int DIALOG_SSL_VALIDATOR = 1;\r
-    private static final int DIALOG_CERT_NOT_SAVED = 2;\r
-\r
-    private static final String TAG = "AuthActivity";\r
-\r
-    private Thread mAuthThread;\r
-    private AuthenticationRunnable mAuthRunnable;\r
-    //private ConnectionCheckerRunnable mConnChkRunnable = null;\r
-    private ConnectionCheckOperation mConnChkRunnable;\r
-    private final Handler mHandler = new Handler();\r
-    private String mBaseUrl;\r
-    \r
-    private static final String STATUS_TEXT = "STATUS_TEXT";\r
-    private static final String STATUS_ICON = "STATUS_ICON";\r
-    private static final String STATUS_CORRECT = "STATUS_CORRECT";\r
-    private static final String IS_SSL_CONN = "IS_SSL_CONN";\r
-    private int mStatusText, mStatusIcon;\r
-    private boolean mStatusCorrect, mIsSslConn;\r
-    private RemoteOperationResult mLastSslUntrustedServerResult;\r
-\r
-    public static final String PARAM_USERNAME = "param_Username";\r
-    public static final String PARAM_HOSTNAME = "param_Hostname";\r
-\r
-    @Override\r
-    protected void onCreate(Bundle savedInstanceState) {\r
-        super.onCreate(savedInstanceState);\r
-        getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
-        setContentView(R.layout.account_setup);\r
-        ImageView iv = (ImageView) findViewById(R.id.refreshButton);\r
-        ImageView iv2 = (ImageView) findViewById(R.id.viewPassword);\r
-        TextView tv = (TextView) findViewById(R.id.host_URL);\r
-        TextView tv2 = (TextView) findViewById(R.id.account_password);\r
-\r
-        if (savedInstanceState != null) {\r
-            mStatusIcon = savedInstanceState.getInt(STATUS_ICON);\r
-            mStatusText = savedInstanceState.getInt(STATUS_TEXT);\r
-            mStatusCorrect = savedInstanceState.getBoolean(STATUS_CORRECT);\r
-            mIsSslConn = savedInstanceState.getBoolean(IS_SSL_CONN);\r
-            setResultIconAndText(mStatusIcon, mStatusText);\r
-            findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);\r
-            if (!mStatusCorrect)\r
-                iv.setVisibility(View.VISIBLE);\r
-            else\r
-                iv.setVisibility(View.INVISIBLE);\r
-\r
-        } else {\r
-            mStatusText = mStatusIcon = 0;\r
-            mStatusCorrect = false;\r
-            mIsSslConn = false;\r
-        }\r
-        iv.setOnClickListener(this);\r
-        iv2.setOnClickListener(this);\r
-        tv.setOnFocusChangeListener(this);\r
-        tv2.setOnFocusChangeListener(this);\r
-\r
-        Button b = (Button) findViewById(R.id.account_register);\r
-        if (b != null) {\r
-            b.setText(String.format(getString(R.string.auth_register), getString(R.string.app_name)));\r
-        }\r
-    }\r
-\r
-    @Override\r
-    protected void onSaveInstanceState(Bundle outState) {\r
-        outState.putInt(STATUS_ICON, mStatusIcon);\r
-        outState.putInt(STATUS_TEXT, mStatusText);\r
-        outState.putBoolean(STATUS_CORRECT, mStatusCorrect);\r
-        super.onSaveInstanceState(outState);\r
-    }\r
-\r
-    @Override\r
-    protected Dialog onCreateDialog(int id) {\r
-        Dialog dialog = null;\r
-        switch (id) {\r
-        case DIALOG_LOGIN_PROGRESS: {\r
-            ProgressDialog working_dialog = new ProgressDialog(this);\r
-            working_dialog.setMessage(getResources().getString(\r
-                    R.string.auth_trying_to_login));\r
-            working_dialog.setIndeterminate(true);\r
-            working_dialog.setCancelable(true);\r
-            working_dialog\r
-                    .setOnCancelListener(new DialogInterface.OnCancelListener() {\r
-                        @Override\r
-                        public void onCancel(DialogInterface dialog) {\r
-                            Log.i(TAG, "Login canceled");\r
-                            if (mAuthThread != null) {\r
-                                mAuthThread.interrupt();\r
-                                finish();\r
-                            }\r
-                        }\r
-                    });\r
-            dialog = working_dialog;\r
-            break;\r
-        }\r
-        case DIALOG_SSL_VALIDATOR: {\r
-            dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);\r
-            break;\r
-        }\r
-        case DIALOG_CERT_NOT_SAVED: {\r
-            AlertDialog.Builder builder = new AlertDialog.Builder(this);\r
-            builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));\r
-            builder.setCancelable(false);\r
-            builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {\r
-                    @Override\r
-                    public void onClick(DialogInterface dialog, int which) {\r
-                        dialog.dismiss();\r
-                    };\r
-                });\r
-            dialog = builder.create();\r
-            break;\r
-        }\r
-        default:\r
-            Log.e(TAG, "Incorrect dialog called with id = " + id);\r
-        }\r
-        return dialog;\r
-    }\r
-\r
-    @Override\r
-    protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {\r
-        switch (id) {\r
-        case DIALOG_LOGIN_PROGRESS:\r
-        case DIALOG_CERT_NOT_SAVED:\r
-            break;\r
-        case DIALOG_SSL_VALIDATOR: {\r
-            ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);\r
-            break;\r
-        }\r
-        default:\r
-            Log.e(TAG, "Incorrect dialog called with id = " + id);\r
-        }\r
-    }\r
-\r
-    public void onAuthenticationResult(boolean success, String message) {\r
-        if (success) {\r
-            TextView username_text = (TextView) findViewById(R.id.account_username), password_text = (TextView) findViewById(R.id.account_password);\r
-\r
-            URL url;\r
-            try {\r
-                url = new URL(message);\r
-            } catch (MalformedURLException e) {\r
-                // should never happen\r
-                Log.e(getClass().getName(), "Malformed URL: " + message);\r
-                return;\r
-            }\r
-\r
-            String username = username_text.getText().toString().trim();\r
-            String accountName = username + "@" + url.getHost();\r
-            if (url.getPort() >= 0) {\r
-                accountName += ":" + url.getPort();\r
-            }\r
-            Account account = new Account(accountName,\r
-                    AccountAuthenticator.ACCOUNT_TYPE);\r
-            AccountManager accManager = AccountManager.get(this);\r
-            accManager.addAccountExplicitly(account, password_text.getText()\r
-                    .toString(), null);\r
-\r
-            // Add this account as default in the preferences, if there is none\r
-            // already\r
-            Account defaultAccount = AccountUtils\r
-                    .getCurrentOwnCloudAccount(this);\r
-            if (defaultAccount == null) {\r
-                SharedPreferences.Editor editor = PreferenceManager\r
-                        .getDefaultSharedPreferences(this).edit();\r
-                editor.putString("select_oc_account", accountName);\r
-                editor.commit();\r
-            }\r
-\r
-            final Intent intent = new Intent();\r
-            intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE,\r
-                    AccountAuthenticator.ACCOUNT_TYPE);\r
-            intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);\r
-            intent.putExtra(AccountManager.KEY_AUTHTOKEN,\r
-                    AccountAuthenticator.ACCOUNT_TYPE);\r
-            intent.putExtra(AccountManager.KEY_USERDATA, username);\r
-\r
-            accManager.setUserData(account,\r
-                    AccountAuthenticator.KEY_OC_VERSION, mConnChkRunnable\r
-                            .getDiscoveredVersion().toString());\r
-            \r
-            accManager.setUserData(account,\r
-                    AccountAuthenticator.KEY_OC_BASE_URL, mBaseUrl);\r
-\r
-            setAccountAuthenticatorResult(intent.getExtras());\r
-            setResult(RESULT_OK, intent);\r
-            Bundle bundle = new Bundle();\r
-            bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);\r
-            //getContentResolver().startSync(ProviderTableMeta.CONTENT_URI,\r
-            //        bundle);\r
-            ContentResolver.requestSync(account, "org.owncloud", bundle);\r
-\r
-            /*\r
-             * if\r
-             * (mConnChkRunnable.getDiscoveredVersion().compareTo(OwnCloudVersion\r
-             * .owncloud_v2) >= 0) { Intent i = new Intent(this,\r
-             * ExtensionsAvailableActivity.class); startActivity(i); }\r
-             */\r
-\r
-            finish();\r
-        } else {\r
-            try {\r
-                dismissDialog(DIALOG_LOGIN_PROGRESS);\r
-            } catch (IllegalArgumentException e) {\r
-                // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens\r
-            }\r
-            TextView tv = (TextView) findViewById(R.id.account_username);\r
-            tv.setError(message + "        ");  // the extra spaces are a workaround for an ugly bug: \r
-                                                // 1. insert wrong credentials and connect\r
-                                                // 2. put the focus on the user name field with using hardware controls (don't touch the screen); the error is shown UNDER the field\r
-                                                // 3. touch the user name field; the software keyboard appears; the error popup is moved OVER the field and SHRINKED in width, losing the last word\r
-                                                // Seen, at least, in Android 2.x devices\r
-        }\r
-    }\r
-    public void onCancelClick(View view) {\r
-        setResult(RESULT_CANCELED);\r
-        finish();\r
-    }\r
-    \r
-    public void onOkClick(View view) {\r
-        String prefix = "";\r
-        String url = ((TextView) findViewById(R.id.host_URL)).getText()\r
-                .toString().trim();\r
-        if (mIsSslConn) {\r
-            prefix = "https://";\r
-        } else {\r
-            prefix = "http://";\r
-        }\r
-        if (url.toLowerCase().startsWith("http://")\r
-                || url.toLowerCase().startsWith("https://")) {\r
-            prefix = "";\r
-        }\r
-        continueConnection(prefix);\r
-    }\r
-    \r
-    public void onRegisterClick(View view) {\r
-        Intent register = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_account_register)));\r
-        setResult(RESULT_CANCELED);\r
-        startActivity(register);\r
-    }\r
-\r
-    private void continueConnection(String prefix) {\r
-        String url = ((TextView) findViewById(R.id.host_URL)).getText()\r
-                .toString().trim();\r
-        String username = ((TextView) findViewById(R.id.account_username))\r
-                .getText().toString();\r
-        String password = ((TextView) findViewById(R.id.account_password))\r
-                .getText().toString();\r
-        if (url.endsWith("/"))\r
-            url = url.substring(0, url.length() - 1);\r
-\r
-        URL uri = null;\r
-        String webdav_path = AccountUtils.getWebdavPath(mConnChkRunnable\r
-                .getDiscoveredVersion());\r
-        \r
-        if (webdav_path == null) {\r
-            onAuthenticationResult(false, getString(R.string.auth_bad_oc_version_title));\r
-            return;\r
-        }\r
-        \r
-        try {\r
-            mBaseUrl = prefix + url;\r
-            String url_str = prefix + url + webdav_path;\r
-            uri = new URL(url_str);\r
-        } catch (MalformedURLException e) {\r
-            // should never happen\r
-            onAuthenticationResult(false, getString(R.string.auth_incorrect_address_title));\r
-            return;\r
-        }\r
-\r
-        showDialog(DIALOG_LOGIN_PROGRESS);\r
-        mAuthRunnable = new AuthenticationRunnable(uri, username, password, this);\r
-        mAuthRunnable.setOnAuthenticationResultListener(this, mHandler);\r
-        mAuthThread = new Thread(mAuthRunnable);\r
-        mAuthThread.start();\r
-    }\r
-\r
-    @Override\r
-    public void onConnectionCheckResult(ResultType type) {\r
-        mStatusText = mStatusIcon = 0;\r
-        mStatusCorrect = false;\r
-        String t_url = ((TextView) findViewById(R.id.host_URL)).getText()\r
-                .toString().trim().toLowerCase();\r
-\r
-        switch (type) {\r
-        case OK_SSL:\r
-            mIsSslConn = true;\r
-            mStatusIcon = android.R.drawable.ic_secure;\r
-            mStatusText = R.string.auth_secure_connection;\r
-            mStatusCorrect = true;\r
-            break;\r
-        case OK_NO_SSL:\r
-            mIsSslConn = false;\r
-            mStatusCorrect = true;\r
-            if (t_url.startsWith("http://") ) {\r
-                mStatusText = R.string.auth_connection_established;\r
-                mStatusIcon = R.drawable.ic_ok;\r
-            } else {\r
-                mStatusText = R.string.auth_nossl_plain_ok_title;\r
-                mStatusIcon = android.R.drawable.ic_partial_secure;\r
-            }\r
-            break;\r
-        case BAD_OC_VERSION:\r
-            mStatusIcon = R.drawable.common_error;\r
-            mStatusText = R.string.auth_bad_oc_version_title;\r
-            break;\r
-        case WRONG_CONNECTION:\r
-            mStatusIcon = R.drawable.common_error;\r
-            mStatusText = R.string.auth_wrong_connection_title;\r
-            break;\r
-        case TIMEOUT:\r
-            mStatusIcon = R.drawable.common_error;\r
-            mStatusText = R.string.auth_timeout_title;\r
-            break;\r
-        case INCORRECT_ADDRESS:\r
-            mStatusIcon = R.drawable.common_error;\r
-            mStatusText = R.string.auth_incorrect_address_title;\r
-            break;\r
-        case SSL_UNVERIFIED_SERVER:\r
-            mStatusIcon = R.drawable.common_error;\r
-            mStatusText = R.string.auth_ssl_unverified_server_title;\r
-            break;\r
-        case SSL_INIT_ERROR:\r
-            mStatusIcon = R.drawable.common_error;\r
-            mStatusText = R.string.auth_ssl_general_error_title;\r
-            break;\r
-        case HOST_NOT_AVAILABLE:\r
-            mStatusIcon = R.drawable.common_error;\r
-            mStatusText = R.string.auth_unknown_host_title;\r
-            break;\r
-        case NO_NETWORK_CONNECTION:\r
-            mStatusIcon = R.drawable.no_network;\r
-            mStatusText = R.string.auth_no_net_conn_title;\r
-            break;\r
-        case INSTANCE_NOT_CONFIGURED:\r
-            mStatusIcon = R.drawable.common_error;\r
-            mStatusText = R.string.auth_not_configured_title;\r
-            break;\r
-        case UNKNOWN_ERROR:\r
-            mStatusIcon = R.drawable.common_error;\r
-            mStatusText = R.string.auth_unknown_error_title;\r
-            break;\r
-        case FILE_NOT_FOUND:\r
-            mStatusIcon = R.drawable.common_error;\r
-            mStatusText = R.string.auth_incorrect_path_title;\r
-            break;\r
-        default:\r
-            Log.e(TAG, "Incorrect connection checker result type: " + type);\r
-        }\r
-        setResultIconAndText(mStatusIcon, mStatusText);\r
-        if (!mStatusCorrect)\r
-            findViewById(R.id.refreshButton).setVisibility(View.VISIBLE);\r
-        else\r
-            findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE);\r
-        findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);\r
-    }\r
-\r
-    @Override\r
-    public void onFocusChange(View view, boolean hasFocus) {\r
-        if (view.getId() == R.id.host_URL) {\r
-            if (!hasFocus) {\r
-                TextView tv = ((TextView) findViewById(R.id.host_URL));\r
-                String uri = tv.getText().toString().trim();\r
-                if (uri.length() != 0) {\r
-                    setResultIconAndText(R.drawable.progress_small,\r
-                            R.string.auth_testing_connection);\r
-                    //mConnChkRunnable = new ConnectionCheckerRunnable(uri, this);\r
-                    mConnChkRunnable = new ConnectionCheckOperation(uri, this);\r
-                    //mConnChkRunnable.setListener(this, mHandler);\r
-                    //mAuthThread = new Thread(mConnChkRunnable);\r
-                    //mAuthThread.start();\r
-                       WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this);\r
-                    mAuthThread = mConnChkRunnable.execute(client, this, mHandler);\r
-                } else {\r
-                    findViewById(R.id.refreshButton).setVisibility(\r
-                            View.INVISIBLE);\r
-                    setResultIconAndText(0, 0);\r
-                }\r
-            } else {\r
-                // avoids that the 'connect' button can be clicked if the test was previously passed\r
-                findViewById(R.id.buttonOK).setEnabled(false); \r
-            }\r
-        } else if (view.getId() == R.id.account_password) {\r
-            ImageView iv = (ImageView) findViewById(R.id.viewPassword);\r
-            if (hasFocus) {\r
-                iv.setVisibility(View.VISIBLE);\r
-            } else {\r
-                TextView v = (TextView) findViewById(R.id.account_password);\r
-                int input_type = InputType.TYPE_CLASS_TEXT\r
-                        | InputType.TYPE_TEXT_VARIATION_PASSWORD;\r
-                v.setInputType(input_type);\r
-                iv.setVisibility(View.INVISIBLE);\r
-            }\r
-        }\r
-    }\r
-\r
-    private void setResultIconAndText(int drawable_id, int text_id) {\r
-        ImageView iv = (ImageView) findViewById(R.id.action_indicator);\r
-        TextView tv = (TextView) findViewById(R.id.status_text);\r
-\r
-        if (drawable_id == 0 && text_id == 0) {\r
-            iv.setVisibility(View.INVISIBLE);\r
-            tv.setVisibility(View.INVISIBLE);\r
-        } else {\r
-            iv.setImageResource(drawable_id);\r
-            tv.setText(text_id);\r
-            iv.setVisibility(View.VISIBLE);\r
-            tv.setVisibility(View.VISIBLE);\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void onClick(View v) {\r
-        if (v.getId() == R.id.refreshButton) {\r
-            onFocusChange(findViewById(R.id.host_URL), false);\r
-        } else if (v.getId() == R.id.viewPassword) {\r
-            EditText view = (EditText) findViewById(R.id.account_password);\r
-            int selectionStart = view.getSelectionStart();\r
-            int selectionEnd = view.getSelectionEnd();\r
-            int input_type = view.getInputType();\r
-            if ((input_type & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {\r
-                input_type = InputType.TYPE_CLASS_TEXT\r
-                        | InputType.TYPE_TEXT_VARIATION_PASSWORD;\r
-            } else {\r
-                input_type = InputType.TYPE_CLASS_TEXT\r
-                        | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;\r
-            }\r
-            view.setInputType(input_type);\r
-            view.setSelection(selectionStart, selectionEnd);\r
-        }\r
-    }\r
-\r
-       @Override\r
-       public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {\r
-               if (operation.equals(mConnChkRunnable)) {\r
-                   \r
-               mStatusText = mStatusIcon = 0;\r
-               mStatusCorrect = false;\r
-               String t_url = ((TextView) findViewById(R.id.host_URL)).getText()\r
-                       .toString().trim().toLowerCase();\r
-               \r
-               switch (result.getCode()) {\r
-               case OK_SSL:\r
-                   mIsSslConn = true;\r
-                   mStatusIcon = android.R.drawable.ic_secure;\r
-                   mStatusText = R.string.auth_secure_connection;\r
-                   mStatusCorrect = true;\r
-                   break;\r
-                   \r
-               case OK_NO_SSL:\r
-               case OK:\r
-                   mIsSslConn = false;\r
-                   mStatusCorrect = true;\r
-                   if (t_url.startsWith("http://") ) {\r
-                       mStatusText = R.string.auth_connection_established;\r
-                       mStatusIcon = R.drawable.ic_ok;\r
-                   } else {\r
-                       mStatusText = R.string.auth_nossl_plain_ok_title;\r
-                       mStatusIcon = android.R.drawable.ic_partial_secure;\r
-                   }\r
-                   break;\r
-               \r
-                   \r
-               case BAD_OC_VERSION:\r
-                   mStatusIcon = R.drawable.common_error;\r
-                   mStatusText = R.string.auth_bad_oc_version_title;\r
-                   break;\r
-               case WRONG_CONNECTION:\r
-                   mStatusIcon = R.drawable.common_error;\r
-                   mStatusText = R.string.auth_wrong_connection_title;\r
-                   break;\r
-               case TIMEOUT:\r
-                   mStatusIcon = R.drawable.common_error;\r
-                   mStatusText = R.string.auth_timeout_title;\r
-                   break;\r
-               case INCORRECT_ADDRESS:\r
-                   mStatusIcon = R.drawable.common_error;\r
-                   mStatusText = R.string.auth_incorrect_address_title;\r
-                   break;\r
-                   \r
-            case SSL_RECOVERABLE_PEER_UNVERIFIED:\r
-                mStatusIcon = R.drawable.common_error;\r
-                mStatusText = R.string.auth_ssl_unverified_server_title;\r
-                mLastSslUntrustedServerResult = result;\r
-                showDialog(DIALOG_SSL_VALIDATOR); \r
-                break;\r
-                   \r
-            case SSL_ERROR:\r
-                mStatusIcon = R.drawable.common_error;\r
-                mStatusText = R.string.auth_ssl_general_error_title;\r
-                break;\r
-                \r
-               case HOST_NOT_AVAILABLE:\r
-                   mStatusIcon = R.drawable.common_error;\r
-                   mStatusText = R.string.auth_unknown_host_title;\r
-                   break;\r
-               case NO_NETWORK_CONNECTION:\r
-                   mStatusIcon = R.drawable.no_network;\r
-                   mStatusText = R.string.auth_no_net_conn_title;\r
-                   break;\r
-               case INSTANCE_NOT_CONFIGURED:\r
-                   mStatusIcon = R.drawable.common_error;\r
-                   mStatusText = R.string.auth_not_configured_title;\r
-                   break;\r
-               case FILE_NOT_FOUND:\r
-                   mStatusIcon = R.drawable.common_error;\r
-                   mStatusText = R.string.auth_incorrect_path_title;\r
-                   break;\r
-            case UNHANDLED_HTTP_CODE:\r
-            case UNKNOWN_ERROR:\r
-                mStatusIcon = R.drawable.common_error;\r
-                mStatusText = R.string.auth_unknown_error_title;\r
-                break;\r
-               default:\r
-                   Log.e(TAG, "Incorrect connection checker result type: " + result.getHttpCode());\r
-               }\r
-               setResultIconAndText(mStatusIcon, mStatusText);\r
-               if (!mStatusCorrect)\r
-                   findViewById(R.id.refreshButton).setVisibility(View.VISIBLE);\r
-               else\r
-                   findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE);\r
-               findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);\r
-               }\r
-       }\r
-\r
-       \r
-    public void onSavedCertificate() {\r
-        mAuthThread = mConnChkRunnable.retry(this, mHandler);                \r
-    }\r
-\r
-    @Override\r
-    public void onFailedSavingCertificate() {\r
-        showDialog(DIALOG_CERT_NOT_SAVED);\r
-    }\r
-    \r
-}\r
+/* ownCloud Android client application
+ *   Copyright (C) 2012  Bartek Przybylski
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License 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.net.MalformedURLException;
+import java.net.URL;
+
+import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.authenticator.AccountAuthenticator;
+import com.owncloud.android.authenticator.AuthenticationRunnable;
+import com.owncloud.android.authenticator.OnAuthenticationResultListener;
+import com.owncloud.android.authenticator.OnConnectCheckListener;
+import com.owncloud.android.ui.dialog.SslValidatorDialog;
+import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;
+import com.owncloud.android.network.OwnCloudClientUtils;
+import com.owncloud.android.operations.ConnectionCheckOperation;
+import com.owncloud.android.operations.OnRemoteOperationListener;
+import com.owncloud.android.operations.RemoteOperation;
+import com.owncloud.android.operations.RemoteOperationResult;
+
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorActivity;
+import android.accounts.AccountManager;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.ContentResolver;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.preference.PreferenceManager;
+import android.text.InputType;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnFocusChangeListener;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.TextView;
+import com.owncloud.android.R;
+
+import eu.alefzero.webdav.WebdavClient;
+
+/**
+ * This Activity is used to add an ownCloud account to the App
+ * 
+ * @author Bartek Przybylski
+ * 
+ */
+public class AuthenticatorActivity extends AccountAuthenticatorActivity
+        implements OnAuthenticationResultListener, OnConnectCheckListener, OnRemoteOperationListener, OnSslValidatorListener, 
+        OnFocusChangeListener, OnClickListener {
+
+    private static final int DIALOG_LOGIN_PROGRESS = 0;
+    private static final int DIALOG_SSL_VALIDATOR = 1;
+    private static final int DIALOG_CERT_NOT_SAVED = 2;
+
+    private static final String TAG = "AuthActivity";
+
+    private Thread mAuthThread;
+    private AuthenticationRunnable mAuthRunnable;
+    //private ConnectionCheckerRunnable mConnChkRunnable = null;
+    private ConnectionCheckOperation mConnChkRunnable;
+    private final Handler mHandler = new Handler();
+    private String mBaseUrl;
+    
+    private static final String STATUS_TEXT = "STATUS_TEXT";
+    private static final String STATUS_ICON = "STATUS_ICON";
+    private static final String STATUS_CORRECT = "STATUS_CORRECT";
+    private static final String IS_SSL_CONN = "IS_SSL_CONN";
+    private int mStatusText, mStatusIcon;
+    private boolean mStatusCorrect, mIsSslConn;
+    private RemoteOperationResult mLastSslUntrustedServerResult;
+
+    public static final String PARAM_USERNAME = "param_Username";
+    public static final String PARAM_HOSTNAME = "param_Hostname";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+        setContentView(R.layout.account_setup);
+        ImageView iv = (ImageView) findViewById(R.id.refreshButton);
+        ImageView iv2 = (ImageView) findViewById(R.id.viewPassword);
+        TextView tv = (TextView) findViewById(R.id.host_URL);
+        TextView tv2 = (TextView) findViewById(R.id.account_password);
+
+        if (savedInstanceState != null) {
+            mStatusIcon = savedInstanceState.getInt(STATUS_ICON);
+            mStatusText = savedInstanceState.getInt(STATUS_TEXT);
+            mStatusCorrect = savedInstanceState.getBoolean(STATUS_CORRECT);
+            mIsSslConn = savedInstanceState.getBoolean(IS_SSL_CONN);
+            setResultIconAndText(mStatusIcon, mStatusText);
+            findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);
+            if (!mStatusCorrect)
+                iv.setVisibility(View.VISIBLE);
+            else
+                iv.setVisibility(View.INVISIBLE);
+
+        } else {
+            mStatusText = mStatusIcon = 0;
+            mStatusCorrect = false;
+            mIsSslConn = false;
+        }
+        iv.setOnClickListener(this);
+        iv2.setOnClickListener(this);
+        tv.setOnFocusChangeListener(this);
+        tv2.setOnFocusChangeListener(this);
+
+        Button b = (Button) findViewById(R.id.account_register);
+        if (b != null) {
+            b.setText(String.format(getString(R.string.auth_register), getString(R.string.app_name)));
+        }
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        outState.putInt(STATUS_ICON, mStatusIcon);
+        outState.putInt(STATUS_TEXT, mStatusText);
+        outState.putBoolean(STATUS_CORRECT, mStatusCorrect);
+        super.onSaveInstanceState(outState);
+    }
+
+    @Override
+    protected Dialog onCreateDialog(int id) {
+        Dialog dialog = null;
+        switch (id) {
+        case DIALOG_LOGIN_PROGRESS: {
+            ProgressDialog working_dialog = new ProgressDialog(this);
+            working_dialog.setMessage(getResources().getString(
+                    R.string.auth_trying_to_login));
+            working_dialog.setIndeterminate(true);
+            working_dialog.setCancelable(true);
+            working_dialog
+                    .setOnCancelListener(new DialogInterface.OnCancelListener() {
+                        @Override
+                        public void onCancel(DialogInterface dialog) {
+                            Log_OC.i(TAG, "Login canceled");
+                            if (mAuthThread != null) {
+                                mAuthThread.interrupt();
+                                finish();
+                            }
+                        }
+                    });
+            dialog = working_dialog;
+            break;
+        }
+        case DIALOG_SSL_VALIDATOR: {
+            dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);
+            break;
+        }
+        case DIALOG_CERT_NOT_SAVED: {
+            AlertDialog.Builder builder = new AlertDialog.Builder(this);
+            builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));
+            builder.setCancelable(false);
+            builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        dialog.dismiss();
+                    };
+                });
+            dialog = builder.create();
+            break;
+        }
+        default:
+            Log_OC.e(TAG, "Incorrect dialog called with id = " + id);
+        }
+        return dialog;
+    }
+
+    @Override
+    protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
+        switch (id) {
+        case DIALOG_LOGIN_PROGRESS:
+        case DIALOG_CERT_NOT_SAVED:
+            break;
+        case DIALOG_SSL_VALIDATOR: {
+            ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);
+            break;
+        }
+        default:
+            Log_OC.e(TAG, "Incorrect dialog called with id = " + id);
+        }
+    }
+
+    public void onAuthenticationResult(boolean success, String message) {
+        if (success) {
+            TextView username_text = (TextView) findViewById(R.id.account_username), password_text = (TextView) findViewById(R.id.account_password);
+
+            URL url;
+            try {
+                url = new URL(message);
+            } catch (MalformedURLException e) {
+                // should never happen
+                Log_OC.e(getClass().getName(), "Malformed URL: " + message);
+                return;
+            }
+
+            String username = username_text.getText().toString().trim();
+            String accountName = username + "@" + url.getHost();
+            if (url.getPort() >= 0) {
+                accountName += ":" + url.getPort();
+            }
+            Account account = new Account(accountName,
+                    AccountAuthenticator.ACCOUNT_TYPE);
+            AccountManager accManager = AccountManager.get(this);
+            accManager.addAccountExplicitly(account, password_text.getText()
+                    .toString(), null);
+
+            // Add this account as default in the preferences, if there is none
+            // already
+            Account defaultAccount = AccountUtils
+                    .getCurrentOwnCloudAccount(this);
+            if (defaultAccount == null) {
+                SharedPreferences.Editor editor = PreferenceManager
+                        .getDefaultSharedPreferences(this).edit();
+                editor.putString("select_oc_account", accountName);
+                editor.commit();
+            }
+
+            final Intent intent = new Intent();
+            intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE,
+                    AccountAuthenticator.ACCOUNT_TYPE);
+            intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
+            intent.putExtra(AccountManager.KEY_AUTHTOKEN,
+                    AccountAuthenticator.ACCOUNT_TYPE);
+            intent.putExtra(AccountManager.KEY_USERDATA, username);
+
+            accManager.setUserData(account,
+                    AccountAuthenticator.KEY_OC_VERSION, mConnChkRunnable
+                            .getDiscoveredVersion().toString());
+            
+            accManager.setUserData(account,
+                    AccountAuthenticator.KEY_OC_BASE_URL, mBaseUrl);
+
+            setAccountAuthenticatorResult(intent.getExtras());
+            setResult(RESULT_OK, intent);
+            Bundle bundle = new Bundle();
+            bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+            //getContentResolver().startSync(ProviderTableMeta.CONTENT_URI,
+            //        bundle);
+            ContentResolver.requestSync(account, "org.owncloud", bundle);
+
+            /*
+             * if
+             * (mConnChkRunnable.getDiscoveredVersion().compareTo(OwnCloudVersion
+             * .owncloud_v2) >= 0) { Intent i = new Intent(this,
+             * ExtensionsAvailableActivity.class); startActivity(i); }
+             */
+
+            finish();
+        } else {
+            try {
+                dismissDialog(DIALOG_LOGIN_PROGRESS);
+            } catch (IllegalArgumentException e) {
+                // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens
+            }
+            TextView tv = (TextView) findViewById(R.id.account_username);
+            tv.setError(message + "        ");  // the extra spaces are a workaround for an ugly bug: 
+                                                // 1. insert wrong credentials and connect
+                                                // 2. put the focus on the user name field with using hardware controls (don't touch the screen); the error is shown UNDER the field
+                                                // 3. touch the user name field; the software keyboard appears; the error popup is moved OVER the field and SHRINKED in width, losing the last word
+                                                // Seen, at least, in Android 2.x devices
+        }
+    }
+    public void onCancelClick(View view) {
+        setResult(RESULT_CANCELED);
+        finish();
+    }
+    
+    public void onOkClick(View view) {
+        String prefix = "";
+        String url = ((TextView) findViewById(R.id.host_URL)).getText()
+                .toString().trim();
+        if (mIsSslConn) {
+            prefix = "https://";
+        } else {
+            prefix = "http://";
+        }
+        if (url.toLowerCase().startsWith("http://")
+                || url.toLowerCase().startsWith("https://")) {
+            prefix = "";
+        }
+        continueConnection(prefix);
+    }
+    
+    public void onRegisterClick(View view) {
+        Intent register = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_account_register)));
+        setResult(RESULT_CANCELED);
+        startActivity(register);
+    }
+
+    private void continueConnection(String prefix) {
+        String url = ((TextView) findViewById(R.id.host_URL)).getText()
+                .toString().trim();
+        String username = ((TextView) findViewById(R.id.account_username))
+                .getText().toString();
+        String password = ((TextView) findViewById(R.id.account_password))
+                .getText().toString();
+        if (url.endsWith("/"))
+            url = url.substring(0, url.length() - 1);
+
+        URL uri = null;
+        String webdav_path = AccountUtils.getWebdavPath(mConnChkRunnable
+                .getDiscoveredVersion());
+        
+        if (webdav_path == null) {
+            onAuthenticationResult(false, getString(R.string.auth_bad_oc_version_title));
+            return;
+        }
+        
+        try {
+            mBaseUrl = prefix + url;
+            String url_str = prefix + url + webdav_path;
+            uri = new URL(url_str);
+        } catch (MalformedURLException e) {
+            // should never happen
+            onAuthenticationResult(false, getString(R.string.auth_incorrect_address_title));
+            return;
+        }
+
+        showDialog(DIALOG_LOGIN_PROGRESS);
+        mAuthRunnable = new AuthenticationRunnable(uri, username, password, this);
+        mAuthRunnable.setOnAuthenticationResultListener(this, mHandler);
+        mAuthThread = new Thread(mAuthRunnable);
+        mAuthThread.start();
+    }
+
+    @Override
+    public void onConnectionCheckResult(ResultType type) {
+        mStatusText = mStatusIcon = 0;
+        mStatusCorrect = false;
+        String t_url = ((TextView) findViewById(R.id.host_URL)).getText()
+                .toString().trim().toLowerCase();
+
+        switch (type) {
+        case OK_SSL:
+            mIsSslConn = true;
+            mStatusIcon = android.R.drawable.ic_secure;
+            mStatusText = R.string.auth_secure_connection;
+            mStatusCorrect = true;
+            break;
+        case OK_NO_SSL:
+            mIsSslConn = false;
+            mStatusCorrect = true;
+            if (t_url.startsWith("http://") ) {
+                mStatusText = R.string.auth_connection_established;
+                mStatusIcon = R.drawable.ic_ok;
+            } else {
+                mStatusText = R.string.auth_nossl_plain_ok_title;
+                mStatusIcon = android.R.drawable.ic_partial_secure;
+            }
+            break;
+        case BAD_OC_VERSION:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_bad_oc_version_title;
+            break;
+        case WRONG_CONNECTION:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_wrong_connection_title;
+            break;
+        case TIMEOUT:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_timeout_title;
+            break;
+        case INCORRECT_ADDRESS:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_incorrect_address_title;
+            break;
+        case SSL_UNVERIFIED_SERVER:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_ssl_unverified_server_title;
+            break;
+        case SSL_INIT_ERROR:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_ssl_general_error_title;
+            break;
+        case HOST_NOT_AVAILABLE:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_unknown_host_title;
+            break;
+        case NO_NETWORK_CONNECTION:
+            mStatusIcon = R.drawable.no_network;
+            mStatusText = R.string.auth_no_net_conn_title;
+            break;
+        case INSTANCE_NOT_CONFIGURED:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_not_configured_title;
+            break;
+        case UNKNOWN_ERROR:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_unknown_error_title;
+            break;
+        case FILE_NOT_FOUND:
+            mStatusIcon = R.drawable.common_error;
+            mStatusText = R.string.auth_incorrect_path_title;
+            break;
+        default:
+            Log_OC.e(TAG, "Incorrect connection checker result type: " + type);
+        }
+        setResultIconAndText(mStatusIcon, mStatusText);
+        if (!mStatusCorrect)
+            findViewById(R.id.refreshButton).setVisibility(View.VISIBLE);
+        else
+            findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE);
+        findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);
+    }
+
+    @Override
+    public void onFocusChange(View view, boolean hasFocus) {
+        if (view.getId() == R.id.host_URL) {
+            if (!hasFocus) {
+                TextView tv = ((TextView) findViewById(R.id.host_URL));
+                String uri = tv.getText().toString().trim();
+                if (uri.length() != 0) {
+                    setResultIconAndText(R.drawable.progress_small,
+                            R.string.auth_testing_connection);
+                    //mConnChkRunnable = new ConnectionCheckerRunnable(uri, this);
+                    mConnChkRunnable = new ConnectionCheckOperation(uri, this);
+                    //mConnChkRunnable.setListener(this, mHandler);
+                    //mAuthThread = new Thread(mConnChkRunnable);
+                    //mAuthThread.start();
+                       WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this);
+                    mAuthThread = mConnChkRunnable.execute(client, this, mHandler);
+                } else {
+                    findViewById(R.id.refreshButton).setVisibility(
+                            View.INVISIBLE);
+                    setResultIconAndText(0, 0);
+                }
+            } else {
+                // avoids that the 'connect' button can be clicked if the test was previously passed
+                findViewById(R.id.buttonOK).setEnabled(false); 
+            }
+        } else if (view.getId() == R.id.account_password) {
+            ImageView iv = (ImageView) findViewById(R.id.viewPassword);
+            if (hasFocus) {
+                iv.setVisibility(View.VISIBLE);
+            } else {
+                TextView v = (TextView) findViewById(R.id.account_password);
+                int input_type = InputType.TYPE_CLASS_TEXT
+                        | InputType.TYPE_TEXT_VARIATION_PASSWORD;
+                v.setInputType(input_type);
+                iv.setVisibility(View.INVISIBLE);
+            }
+        }
+    }
+
+    private void setResultIconAndText(int drawable_id, int text_id) {
+        ImageView iv = (ImageView) findViewById(R.id.action_indicator);
+        TextView tv = (TextView) findViewById(R.id.status_text);
+
+        if (drawable_id == 0 && text_id == 0) {
+            iv.setVisibility(View.INVISIBLE);
+            tv.setVisibility(View.INVISIBLE);
+        } else {
+            iv.setImageResource(drawable_id);
+            tv.setText(text_id);
+            iv.setVisibility(View.VISIBLE);
+            tv.setVisibility(View.VISIBLE);
+        }
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v.getId() == R.id.refreshButton) {
+            onFocusChange(findViewById(R.id.host_URL), false);
+        } else if (v.getId() == R.id.viewPassword) {
+            EditText view = (EditText) findViewById(R.id.account_password);
+            int selectionStart = view.getSelectionStart();
+            int selectionEnd = view.getSelectionEnd();
+            int input_type = view.getInputType();
+            if ((input_type & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
+                input_type = InputType.TYPE_CLASS_TEXT
+                        | InputType.TYPE_TEXT_VARIATION_PASSWORD;
+            } else {
+                input_type = InputType.TYPE_CLASS_TEXT
+                        | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
+            }
+            view.setInputType(input_type);
+            view.setSelection(selectionStart, selectionEnd);
+        }
+    }
+
+       @Override
+       public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+               if (operation.equals(mConnChkRunnable)) {
+                   
+               mStatusText = mStatusIcon = 0;
+               mStatusCorrect = false;
+               String t_url = ((TextView) findViewById(R.id.host_URL)).getText()
+                       .toString().trim().toLowerCase();
+               
+               switch (result.getCode()) {
+               case OK_SSL:
+                   mIsSslConn = true;
+                   mStatusIcon = android.R.drawable.ic_secure;
+                   mStatusText = R.string.auth_secure_connection;
+                   mStatusCorrect = true;
+                   break;
+                   
+               case OK_NO_SSL:
+               case OK:
+                   mIsSslConn = false;
+                   mStatusCorrect = true;
+                   if (t_url.startsWith("http://") ) {
+                       mStatusText = R.string.auth_connection_established;
+                       mStatusIcon = R.drawable.ic_ok;
+                   } else {
+                       mStatusText = R.string.auth_nossl_plain_ok_title;
+                       mStatusIcon = android.R.drawable.ic_partial_secure;
+                   }
+                   break;
+               
+                   
+               case BAD_OC_VERSION:
+                   mStatusIcon = R.drawable.common_error;
+                   mStatusText = R.string.auth_bad_oc_version_title;
+                   break;
+               case WRONG_CONNECTION:
+                   mStatusIcon = R.drawable.common_error;
+                   mStatusText = R.string.auth_wrong_connection_title;
+                   break;
+               case TIMEOUT:
+                   mStatusIcon = R.drawable.common_error;
+                   mStatusText = R.string.auth_timeout_title;
+                   break;
+               case INCORRECT_ADDRESS:
+                   mStatusIcon = R.drawable.common_error;
+                   mStatusText = R.string.auth_incorrect_address_title;
+                   break;
+                   
+            case SSL_RECOVERABLE_PEER_UNVERIFIED:
+                mStatusIcon = R.drawable.common_error;
+                mStatusText = R.string.auth_ssl_unverified_server_title;
+                mLastSslUntrustedServerResult = result;
+                showDialog(DIALOG_SSL_VALIDATOR); 
+                break;
+                   
+            case SSL_ERROR:
+                mStatusIcon = R.drawable.common_error;
+                mStatusText = R.string.auth_ssl_general_error_title;
+                break;
+                
+               case HOST_NOT_AVAILABLE:
+                   mStatusIcon = R.drawable.common_error;
+                   mStatusText = R.string.auth_unknown_host_title;
+                   break;
+               case NO_NETWORK_CONNECTION:
+                   mStatusIcon = R.drawable.no_network;
+                   mStatusText = R.string.auth_no_net_conn_title;
+                   break;
+               case INSTANCE_NOT_CONFIGURED:
+                   mStatusIcon = R.drawable.common_error;
+                   mStatusText = R.string.auth_not_configured_title;
+                   break;
+               case FILE_NOT_FOUND:
+                   mStatusIcon = R.drawable.common_error;
+                   mStatusText = R.string.auth_incorrect_path_title;
+                   break;
+            case UNHANDLED_HTTP_CODE:
+            case UNKNOWN_ERROR:
+                mStatusIcon = R.drawable.common_error;
+                mStatusText = R.string.auth_unknown_error_title;
+                break;
+               default:
+                   Log_OC.e(TAG, "Incorrect connection checker result type: " + result.getHttpCode());
+               }
+               setResultIconAndText(mStatusIcon, mStatusText);
+               if (!mStatusCorrect)
+                   findViewById(R.id.refreshButton).setVisibility(View.VISIBLE);
+               else
+                   findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE);
+               findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);
+               }
+       }
+
+       
+    public void onSavedCertificate() {
+        mAuthThread = mConnChkRunnable.retry(this, mHandler);                
+    }
+
+    @Override
+    public void onFailedSavingCertificate() {
+        showDialog(DIALOG_CERT_NOT_SAVED);
+    }
+    
+}
index 21aaed8..3ccc07d 100644 (file)
@@ -20,6 +20,7 @@
 package com.owncloud.android.ui.activity;
 
 import com.actionbarsherlock.app.SherlockFragmentActivity;
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.ui.dialog.ConflictsResolveDialog;
@@ -79,7 +80,7 @@ public class ConflictsResolveActivity extends SherlockFragmentActivity implement
                 i.putExtra(FileUploader.KEY_LOCAL_BEHAVIOUR, FileUploader.LOCAL_BEHAVIOUR_MOVE);
                 break;
             default:
-                Log.wtf(TAG, "Unhandled conflict decision " + decision);
+                Log_OC.wtf(TAG, "Unhandled conflict decision " + decision);
                 return;
         }
         i.putExtra(FileUploader.KEY_ACCOUNT, mOCAccount);
index 0522cb8..dc6a507 100644 (file)
@@ -41,6 +41,7 @@ import android.widget.TextView;
 import android.widget.Toast;
 
 import com.actionbarsherlock.app.SherlockFragmentActivity;
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
@@ -182,16 +183,16 @@ public class ErrorsWhileCopyingHandlerActivity  extends SherlockFragmentActivity
     public void onClick(View v) {
         if (v.getId() == R.id.ok) {
             /// perform movement operation in background thread
-            Log.d(TAG, "Clicked MOVE, start movement");
+            Log_OC.d(TAG, "Clicked MOVE, start movement");
             new MoveFilesTask().execute();            
             
         } else if (v.getId() == R.id.cancel) {
             /// just finish
-            Log.d(TAG, "Clicked CANCEL, bye");
+            Log_OC.d(TAG, "Clicked CANCEL, bye");
             finish();
             
         } else {
-            Log.e(TAG, "Clicked phantom button, id: " + v.getId());
+            Log_OC.e(TAG, "Clicked phantom button, id: " + v.getId());
         }
     }
 
index 1933735..12c133c 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
-package com.owncloud.android.ui.activity;\r
-\r
-import android.accounts.Account;\r
-import android.app.Dialog;\r
-import android.app.ProgressDialog;\r
-import android.content.BroadcastReceiver;\r
-import android.content.ComponentName;\r
-import android.content.Context;\r
-import android.content.Intent;\r
-import android.content.IntentFilter;\r
-import android.content.ServiceConnection;\r
-import android.content.res.Configuration;\r
-import android.os.Bundle;\r
-import android.os.IBinder;\r
-import android.support.v4.app.Fragment;\r
-import android.support.v4.app.FragmentTransaction;\r
-import android.util.Log;\r
-\r
-import com.actionbarsherlock.app.ActionBar;\r
-import com.actionbarsherlock.app.SherlockFragmentActivity;\r
-import com.actionbarsherlock.view.MenuItem;\r
-import com.owncloud.android.datamodel.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.FileUploader;\r
-import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;\r
-import com.owncloud.android.ui.fragment.FileDetailFragment;\r
-import com.owncloud.android.ui.fragment.FileFragment;\r
-import com.owncloud.android.ui.preview.PreviewMediaFragment;\r
-\r
-import com.owncloud.android.AccountUtils;\r
-import com.owncloud.android.R;\r
-\r
-/**\r
- * This activity displays the details of a file like its name, its size and so\r
- * on.\r
- * \r
- * @author Bartek Przybylski\r
- * @author David A. Velasco\r
- */\r
-public class FileDetailActivity extends SherlockFragmentActivity implements FileFragment.ContainerActivity {\r
-    \r
-    public static final int DIALOG_SHORT_WAIT = 0;\r
-\r
-    public static final String TAG = FileDetailActivity.class.getSimpleName();\r
-    \r
-    public static final String EXTRA_MODE = "MODE";\r
-    public static final int MODE_DETAILS = 0;\r
-    public static final int MODE_PREVIEW = 1;\r
-\r
-    public static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW";\r
-    \r
-    private boolean mConfigurationChangedToLandscape = false;\r
-    private FileDownloaderBinder mDownloaderBinder = null;\r
-    private ServiceConnection mDownloadConnection, mUploadConnection = null;\r
-    private FileUploaderBinder mUploaderBinder = null;\r
-    private boolean mWaitingToPreview;\r
-    \r
-    private OCFile mFile;\r
-    private Account mAccount;\r
-\r
-    private FileDataStorageManager mStorageManager;\r
-    private DownloadFinishReceiver mDownloadFinishReceiver;\r
-    \r
-\r
-    @Override\r
-    protected void onCreate(Bundle savedInstanceState) {\r
-        super.onCreate(savedInstanceState);\r
-\r
-        mFile = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);\r
-        mAccount = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);\r
-        mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());\r
-        \r
-        // check if configuration changed to large-land ; for a tablet being changed from portrait to landscape when in FileDetailActivity \r
-        Configuration conf = getResources().getConfiguration();\r
-        mConfigurationChangedToLandscape = (conf.orientation == Configuration.ORIENTATION_LANDSCAPE && \r
-                                                (conf.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE\r
-                                           );\r
-\r
-        if (!mConfigurationChangedToLandscape) {\r
-            setContentView(R.layout.file_activity_details);\r
-        \r
-            ActionBar actionBar = getSupportActionBar();\r
-            actionBar.setDisplayHomeAsUpEnabled(true);\r
-\r
-            if (savedInstanceState == null) {\r
-                mWaitingToPreview = false;\r
-                createChildFragment();\r
-            } else {\r
-                mWaitingToPreview = savedInstanceState.getBoolean(KEY_WAITING_TO_PREVIEW);\r
-            }\r
-            \r
-            mDownloadConnection = new DetailsServiceConnection();\r
-            bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);\r
-            mUploadConnection = new DetailsServiceConnection();\r
-            bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);\r
-            \r
-            \r
-        }  else {\r
-            backToDisplayActivity(false);   // the 'back' won't be effective until this.onStart() and this.onResume() are completed;\r
-        }\r
-        \r
-        \r
-    }\r
-\r
-    /**\r
-     * Creates the proper fragment depending upon the state of the handled {@link OCFile} and\r
-     * the requested {@link Intent}.\r
-     */\r
-    private void createChildFragment() {\r
-        int mode = getIntent().getIntExtra(EXTRA_MODE, MODE_PREVIEW); \r
-        \r
-        Fragment newFragment = null;\r
-        if (PreviewMediaFragment.canBePreviewed(mFile) && mode == MODE_PREVIEW) {\r
-            if (mFile.isDown()) {\r
-                newFragment = new PreviewMediaFragment(mFile, mAccount);\r
-            \r
-            } else {\r
-                newFragment = new FileDetailFragment(mFile, mAccount);\r
-                mWaitingToPreview = true;\r
-            }\r
-            \r
-        } else {\r
-            newFragment = new FileDetailFragment(mFile, mAccount);\r
-        }\r
-        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();\r
-        ft.replace(R.id.fragment, newFragment, FileDetailFragment.FTAG);\r
-        ft.commit();\r
-    }\r
-    \r
-\r
-    @Override\r
-    protected void onSaveInstanceState(Bundle outState) {\r
-        super.onSaveInstanceState(outState);\r
-        outState.putBoolean(KEY_WAITING_TO_PREVIEW, mWaitingToPreview);\r
-    }\r
-    \r
-    \r
-    @Override\r
-    public void onPause() {\r
-        super.onPause();\r
-        if (mDownloadFinishReceiver != null) {\r
-            unregisterReceiver(mDownloadFinishReceiver);\r
-            mDownloadFinishReceiver = null;\r
-        }\r
-    }\r
-    \r
-    \r
-    @Override\r
-    public void onResume() {\r
-        super.onResume();\r
-        if (!mConfigurationChangedToLandscape) {\r
-            // TODO this is probably unnecessary\r
-            Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
-            if (fragment != null && fragment instanceof FileDetailFragment) {\r
-                ((FileDetailFragment) fragment).updateFileDetails(false, false);\r
-            }\r
-        }\r
-        // Listen for download messages\r
-        IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_ADDED_MESSAGE);\r
-        downloadIntentFilter.addAction(FileDownloader.DOWNLOAD_FINISH_MESSAGE);\r
-        mDownloadFinishReceiver = new DownloadFinishReceiver();\r
-        registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);\r
-    }\r
-    \r
-    \r
-    /** Defines callbacks for service binding, passed to bindService() */\r
-    private class DetailsServiceConnection implements ServiceConnection {\r
-\r
-        @Override\r
-        public void onServiceConnected(ComponentName component, IBinder service) {\r
-                \r
-            if (component.equals(new ComponentName(FileDetailActivity.this, FileDownloader.class))) {\r
-                Log.d(TAG, "Download service connected");\r
-                mDownloaderBinder = (FileDownloaderBinder) service;\r
-                if (mWaitingToPreview) {\r
-                    requestForDownload();\r
-                }\r
-                    \r
-            } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) {\r
-                Log.d(TAG, "Upload service connected");\r
-                mUploaderBinder = (FileUploaderBinder) service;\r
-            } else {\r
-                return;\r
-            }\r
-            \r
-            Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
-            FileDetailFragment detailsFragment = (fragment instanceof FileDetailFragment) ? (FileDetailFragment) fragment : null;\r
-            if (detailsFragment != null) {\r
-                detailsFragment.listenForTransferProgress();\r
-                detailsFragment.updateFileDetails(mWaitingToPreview, false);   // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais())\r
-            }\r
-        }\r
-\r
-        @Override\r
-        public void onServiceDisconnected(ComponentName component) {\r
-            if (component.equals(new ComponentName(FileDetailActivity.this, FileDownloader.class))) {\r
-                Log.d(TAG, "Download service disconnected");\r
-                mDownloaderBinder = null;\r
-            } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) {\r
-                Log.d(TAG, "Upload service disconnected");\r
-                mUploaderBinder = null;\r
-            }\r
-        }\r
-    };    \r
-    \r
-    \r
-    @Override\r
-    public void onDestroy() {\r
-        super.onDestroy();\r
-        if (mDownloadConnection != null) {\r
-            unbindService(mDownloadConnection);\r
-            mDownloadConnection = null;\r
-        }\r
-        if (mUploadConnection != null) {\r
-            unbindService(mUploadConnection);\r
-            mUploadConnection = null;\r
-        }\r
-    }\r
-    \r
-    \r
-    @Override\r
-    public boolean onOptionsItemSelected(MenuItem item) {\r
-        boolean returnValue = false;\r
-        \r
-        switch(item.getItemId()){\r
-        case android.R.id.home:\r
-            backToDisplayActivity(true);\r
-            returnValue = true;\r
-            break;\r
-        default:\r
-               returnValue = super.onOptionsItemSelected(item);\r
-        }\r
-        \r
-        return returnValue;\r
-    }\r
-\r
-\r
-\r
-    private void backToDisplayActivity(boolean moveToParent) {\r
-        Intent intent = new Intent(this, FileDisplayActivity.class);\r
-        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
-        OCFile targetFile = null;\r
-        if (mFile != null) {\r
-            targetFile = moveToParent ? mStorageManager.getFileById(mFile.getParentId()) : mFile;\r
-        }\r
-        intent.putExtra(FileDetailFragment.EXTRA_FILE, targetFile);\r
-        intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, mAccount);\r
-        startActivity(intent);\r
-        finish();\r
-    }\r
-    \r
-    \r
-    @Override\r
-    protected Dialog onCreateDialog(int id) {\r
-        Dialog dialog = null;\r
-        switch (id) {\r
-        case DIALOG_SHORT_WAIT: {\r
-            ProgressDialog working_dialog = new ProgressDialog(this);\r
-            working_dialog.setMessage(getResources().getString(\r
-                    R.string.wait_a_moment));\r
-            working_dialog.setIndeterminate(true);\r
-            working_dialog.setCancelable(false);\r
-            dialog = working_dialog;\r
-            break;\r
-        }\r
-        default:\r
-            dialog = null;\r
-        }\r
-        return dialog;\r
-    }\r
-    \r
-    \r
-    /**\r
-     * {@inheritDoc}\r
-     */\r
-    @Override\r
-    public void onFileStateChanged() {\r
-        // nothing to do here!\r
-    }\r
-\r
-    \r
-    /**\r
-     * {@inheritDoc}\r
-     */\r
-    @Override\r
-    public FileDownloaderBinder getFileDownloaderBinder() {\r
-        return mDownloaderBinder;\r
-    }\r
-\r
-\r
-    @Override\r
-    public FileUploaderBinder getFileUploaderBinder() {\r
-        return mUploaderBinder;\r
-    }\r
-\r
-\r
-    @Override\r
-    public void showFragmentWithDetails(OCFile file) {\r
-        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
-        transaction.replace(R.id.fragment, new FileDetailFragment(file, mAccount), FileDetailFragment.FTAG); \r
-        transaction.commit();\r
-    }\r
-\r
-    \r
-    private void requestForDownload() {\r
-        if (!mDownloaderBinder.isDownloading(mAccount, mFile)) {\r
-            Intent i = new Intent(this, FileDownloader.class);\r
-            i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount);\r
-            i.putExtra(FileDownloader.EXTRA_FILE, mFile);\r
-            startService(i);\r
-        }\r
-    }\r
-\r
-    \r
-    /**\r
-     * Class waiting for broadcast events from the {@link FielDownloader} service.\r
-     * \r
-     * Updates the UI when a download is started or finished, provided that it is relevant for the\r
-     * current file.\r
-     */\r
-    private class DownloadFinishReceiver extends BroadcastReceiver {\r
-        @Override\r
-        public void onReceive(Context context, Intent intent) {\r
-            boolean sameAccount = isSameAccount(context, intent);\r
-            String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);\r
-            boolean samePath = (mFile != null && mFile.getRemotePath().equals(downloadedRemotePath));\r
-            \r
-            if (sameAccount && samePath) {\r
-                updateChildFragment(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false));\r
-            }\r
-            \r
-            removeStickyBroadcast(intent);\r
-        }\r
-\r
-        private boolean isSameAccount(Context context, Intent intent) {\r
-            String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);\r
-            return (accountName != null && accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name));\r
-        }\r
-    }\r
-\r
-\r
-    public void updateChildFragment(String downloadEvent, String downloadedRemotePath, boolean success) {\r
-        Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
-        if (fragment != null && fragment instanceof FileDetailFragment) {\r
-            FileDetailFragment detailsFragment = (FileDetailFragment) fragment;\r
-            OCFile fileInFragment = detailsFragment.getFile();\r
-            if (fileInFragment != null && !downloadedRemotePath.equals(fileInFragment.getRemotePath())) {\r
-                // this never should happen; fileInFragment should be always equals to mFile, that was compared to downloadedRemotePath in DownloadReceiver \r
-                mWaitingToPreview = false;\r
-                \r
-            } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_ADDED_MESSAGE)) {\r
-                // grants that the progress bar is updated\r
-                detailsFragment.listenForTransferProgress();\r
-                detailsFragment.updateFileDetails(true, false);\r
-                \r
-            } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_FINISH_MESSAGE)) {\r
-                //  refresh the details fragment \r
-                if (success && mWaitingToPreview) {\r
-                    mFile = mStorageManager.getFileById(mFile.getFileId());   // update the file from database, for the local storage path\r
-                    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
-                    transaction.replace(R.id.fragment, new PreviewMediaFragment(mFile, mAccount), FileDetailFragment.FTAG);\r
-                    transaction.commit();\r
-                    mWaitingToPreview = false;\r
-                    \r
-                } else {\r
-                    detailsFragment.updateFileDetails(false, (success));\r
-                    // TODO error message if !success Â¿?\r
-                }\r
-            }\r
-        } // TODO else if (fragment != null && fragment )\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 android.accounts.Account;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentTransaction;
+import android.util.Log;
+
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.SherlockFragmentActivity;
+import com.actionbarsherlock.view.MenuItem;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileDownloader;
+import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+import com.owncloud.android.ui.fragment.FileDetailFragment;
+import com.owncloud.android.ui.fragment.FileFragment;
+import com.owncloud.android.ui.preview.PreviewMediaFragment;
+import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
+
+import com.owncloud.android.R;
+
+/**
+ * This activity displays the details of a file like its name, its size and so
+ * on.
+ * 
+ * @author Bartek Przybylski
+ * @author David A. Velasco
+ */
+public class FileDetailActivity extends SherlockFragmentActivity implements FileFragment.ContainerActivity {
+    
+    public static final int DIALOG_SHORT_WAIT = 0;
+
+    public static final String TAG = FileDetailActivity.class.getSimpleName();
+    
+    public static final String EXTRA_MODE = "MODE";
+    public static final int MODE_DETAILS = 0;
+    public static final int MODE_PREVIEW = 1;
+
+    public static final String KEY_WAITING_TO_PREVIEW = "WAITING_TO_PREVIEW";
+    
+    private boolean mConfigurationChangedToLandscape = false;
+    private FileDownloaderBinder mDownloaderBinder = null;
+    private ServiceConnection mDownloadConnection, mUploadConnection = null;
+    private FileUploaderBinder mUploaderBinder = null;
+    private boolean mWaitingToPreview;
+    
+    private OCFile mFile;
+    private Account mAccount;
+
+    private FileDataStorageManager mStorageManager;
+    private DownloadFinishReceiver mDownloadFinishReceiver;
+    
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mFile = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);
+        mAccount = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);
+        mStorageManager = new FileDataStorageManager(mAccount, getContentResolver());
+        
+        // check if configuration changed to large-land ; for a tablet being changed from portrait to landscape when in FileDetailActivity 
+        Configuration conf = getResources().getConfiguration();
+        mConfigurationChangedToLandscape = (conf.orientation == Configuration.ORIENTATION_LANDSCAPE && 
+                                                (conf.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE
+                                           );
+
+        if (!mConfigurationChangedToLandscape) {
+            setContentView(R.layout.file_activity_details);
+        
+            ActionBar actionBar = getSupportActionBar();
+            actionBar.setDisplayHomeAsUpEnabled(true);
+
+            if (savedInstanceState == null) {
+                mWaitingToPreview = false;
+                createChildFragment();
+            } else {
+                mWaitingToPreview = savedInstanceState.getBoolean(KEY_WAITING_TO_PREVIEW);
+            }
+            
+            mDownloadConnection = new DetailsServiceConnection();
+            bindService(new Intent(this, FileDownloader.class), mDownloadConnection, Context.BIND_AUTO_CREATE);
+            mUploadConnection = new DetailsServiceConnection();
+            bindService(new Intent(this, FileUploader.class), mUploadConnection, Context.BIND_AUTO_CREATE);
+            
+            
+        }  else {
+            backToDisplayActivity(false);   // the 'back' won't be effective until this.onStart() and this.onResume() are completed;
+        }
+        
+    }
+    
+    /**
+     * Creates the proper fragment depending upon the state of the handled {@link OCFile} and
+     * the requested {@link Intent}.
+     */
+    private void createChildFragment() {
+        int mode = getIntent().getIntExtra(EXTRA_MODE, MODE_PREVIEW); 
+        
+        Fragment newFragment = null;
+        if (PreviewMediaFragment.canBePreviewed(mFile) && mode == MODE_PREVIEW) {
+            if (mFile.isDown()) {
+                newFragment = new PreviewMediaFragment(mFile, mAccount);
+            
+            } else {
+                newFragment = new FileDetailFragment(mFile, mAccount);
+                mWaitingToPreview = true;
+            }
+            
+        } else {
+            newFragment = new FileDetailFragment(mFile, mAccount);
+        }
+        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+        ft.replace(R.id.fragment, newFragment, FileDetailFragment.FTAG);
+        ft.commit();
+    }
+    
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putBoolean(KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
+    }
+    
+    
+    @Override
+    public void onPause() {
+        super.onPause();
+        if (mDownloadFinishReceiver != null) {
+            unregisterReceiver(mDownloadFinishReceiver);
+            mDownloadFinishReceiver = null;
+        }
+    }
+
+    
+    @Override
+    public void onResume() {
+        super.onResume();
+        if (!mConfigurationChangedToLandscape) {
+            // TODO this is probably unnecessary
+            Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+            if (fragment != null && fragment instanceof FileDetailFragment) {
+                ((FileDetailFragment) fragment).updateFileDetails(false, false);
+            }
+        }
+        // Listen for download messages
+        IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_ADDED_MESSAGE);
+        downloadIntentFilter.addAction(FileDownloader.DOWNLOAD_FINISH_MESSAGE);
+        mDownloadFinishReceiver = new DownloadFinishReceiver();
+        registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
+    }
+    
+    
+    /** Defines callbacks for service binding, passed to bindService() */
+    private class DetailsServiceConnection implements ServiceConnection {
+
+        @Override
+        public void onServiceConnected(ComponentName component, IBinder service) {
+                
+            if (component.equals(new ComponentName(FileDetailActivity.this, FileDownloader.class))) {
+                Log_OC.d(TAG, "Download service connected");
+                mDownloaderBinder = (FileDownloaderBinder) service;
+                if (mWaitingToPreview) {
+                    requestForDownload();
+                }
+                    
+            } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) {
+                Log_OC.d(TAG, "Upload service connected");
+                mUploaderBinder = (FileUploaderBinder) service;
+            } else {
+                return;
+            }
+            
+            Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+            FileDetailFragment detailsFragment = (fragment instanceof FileDetailFragment) ? (FileDetailFragment) fragment : null;
+            if (detailsFragment != null) {
+                detailsFragment.listenForTransferProgress();
+                detailsFragment.updateFileDetails(mWaitingToPreview, false);   // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais())
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName component) {
+            if (component.equals(new ComponentName(FileDetailActivity.this, FileDownloader.class))) {
+                Log_OC.d(TAG, "Download service disconnected");
+                mDownloaderBinder = null;
+            } else if (component.equals(new ComponentName(FileDetailActivity.this, FileUploader.class))) {
+                Log_OC.d(TAG, "Upload service disconnected");
+                mUploaderBinder = null;
+            }
+        }
+    };    
+    
+    
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (mDownloadConnection != null) {
+            unbindService(mDownloadConnection);
+            mDownloadConnection = null;
+        }
+        if (mUploadConnection != null) {
+            unbindService(mUploadConnection);
+            mUploadConnection = null;
+        }
+    }
+    
+    
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        boolean returnValue = false;
+        
+        switch(item.getItemId()){
+        case android.R.id.home:
+            backToDisplayActivity(true);
+            returnValue = true;
+            break;
+        default:
+            returnValue = super.onOptionsItemSelected(item);
+        }
+        
+        return returnValue;
+    }
+
+    private void backToDisplayActivity(boolean moveToParent) {
+        Intent intent = new Intent(this, FileDisplayActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        OCFile targetFile = null;
+        if (mFile != null) {
+            targetFile = moveToParent ? mStorageManager.getFileById(mFile.getParentId()) : mFile;
+        }
+        intent.putExtra(FileDetailFragment.EXTRA_FILE, targetFile);
+        intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, mAccount);
+        startActivity(intent);
+        finish();
+    }
+    
+    
+    @Override
+    protected Dialog onCreateDialog(int id) {
+        Dialog dialog = null;
+        switch (id) {
+        case DIALOG_SHORT_WAIT: {
+            ProgressDialog working_dialog = new ProgressDialog(this);
+            working_dialog.setMessage(getResources().getString(
+                    R.string.wait_a_moment));
+            working_dialog.setIndeterminate(true);
+            working_dialog.setCancelable(false);
+            dialog = working_dialog;
+            break;
+        }
+        default:
+            dialog = null;
+        }
+        return dialog;
+    }
+    
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onFileStateChanged() {
+        // nothing to do here!
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FileDownloaderBinder getFileDownloaderBinder() {
+        return mDownloaderBinder;
+    }
+
+
+    @Override
+    public FileUploaderBinder getFileUploaderBinder() {
+        return mUploaderBinder;
+    }
+
+
+    @Override
+    public void showFragmentWithDetails(OCFile file) {
+        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+        transaction.replace(R.id.fragment, new FileDetailFragment(file, mAccount), FileDetailFragment.FTAG); 
+        transaction.commit();
+    }
+
+    
+    private void requestForDownload() {
+        if (!mDownloaderBinder.isDownloading(mAccount, mFile)) {
+            Intent i = new Intent(this, FileDownloader.class);
+            i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount);
+            i.putExtra(FileDownloader.EXTRA_FILE, mFile);
+            startService(i);
+        }
+    }
+
+    
+    /**
+     * Class waiting for broadcast events from the {@link FielDownloader} service.
+     * 
+     * Updates the UI when a download is started or finished, provided that it is relevant for the
+     * current file.
+     */
+    private class DownloadFinishReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            boolean sameAccount = isSameAccount(context, intent);
+            String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
+            boolean samePath = (mFile != null && mFile.getRemotePath().equals(downloadedRemotePath));
+            
+            if (sameAccount && samePath) {
+                updateChildFragment(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false));
+            }
+            
+            removeStickyBroadcast(intent);
+        }
+
+        private boolean isSameAccount(Context context, Intent intent) {
+            String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
+            return (accountName != null && accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name));
+        }
+    }
+
+
+    public void updateChildFragment(String downloadEvent, String downloadedRemotePath, boolean success) {
+        Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+        if (fragment != null && fragment instanceof FileDetailFragment) {
+            FileDetailFragment detailsFragment = (FileDetailFragment) fragment;
+            OCFile fileInFragment = detailsFragment.getFile();
+            if (fileInFragment != null && !downloadedRemotePath.equals(fileInFragment.getRemotePath())) {
+                // this never should happen; fileInFragment should be always equals to mFile, that was compared to downloadedRemotePath in DownloadReceiver 
+                mWaitingToPreview = false;
+                
+            } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_ADDED_MESSAGE)) {
+                // grants that the progress bar is updated
+                detailsFragment.listenForTransferProgress();
+                detailsFragment.updateFileDetails(true, false);
+                
+            } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_FINISH_MESSAGE)) {
+                //  refresh the details fragment 
+                if (success && mWaitingToPreview) {
+                    mFile = mStorageManager.getFileById(mFile.getFileId());   // update the file from database, for the local storage path
+                    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+                    transaction.replace(R.id.fragment, new PreviewMediaFragment(mFile, mAccount), FileDetailFragment.FTAG);
+                    transaction.commit();
+                    mWaitingToPreview = false;
+                    
+                } else {
+                    detailsFragment.updateFileDetails(false, (success));
+                    // TODO error message if !success Â¿?
+                }
+            }
+        } // TODO else if (fragment != null && fragment )
+        
+    }
+
+}
index 8e36b9a..d2545c6 100644 (file)
@@ -67,6 +67,8 @@ import com.actionbarsherlock.view.MenuInflater;
 import com.actionbarsherlock.view.MenuItem;
 import com.actionbarsherlock.view.Window;
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.R;
 import com.owncloud.android.authenticator.AccountAuthenticator;
 import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.FileDataStorageManager;
@@ -130,7 +132,6 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
     
     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;
@@ -148,10 +149,9 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
     private OCFile mWaitingToPreview;
     private Handler mHandler;
 
-    
     @Override
     public void onCreate(Bundle savedInstanceState) {
-        Log.d(getClass().toString(), "onCreate() start");
+        Log_OC.d(getClass().toString(), "onCreate() start");
         super.onCreate(savedInstanceState);
 
         /// Load of parameters from received intent
@@ -244,7 +244,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         //showChangeLog();
         mBackFromCreatingFirstAccount = false;
         
-        Log.d(getClass().toString(), "onCreate() end");
+        Log_OC.d(getClass().toString(), "onCreate() end");
     }
 
     
@@ -355,31 +355,9 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         MenuInflater inflater = getSherlock().getMenuInflater();
             inflater.inflate(R.menu.main_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;
@@ -402,10 +380,6 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
                 startActivity(settingsIntent);
                 break;
             }
-            case R.id.action_about_app: {
-                showDialog(DIALOG_ABOUT_APP);
-                break;
-            }
             case android.R.id.home: {
                 if(mCurrentDir != null && mCurrentDir.getParentId() != 0){
                     onBackPressed(); 
@@ -480,7 +454,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
             startService(i);
             
         } else {
-            Log.d("FileDisplay", "User clicked on 'Update' with no selection");
+            Log_OC.d("FileDisplay", "User clicked on 'Update' with no selection");
             Toast t = Toast.makeText(this, getString(R.string.filedisplay_no_file_selected), Toast.LENGTH_LONG);
             t.show();
             return;
@@ -502,12 +476,12 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
                 filepath = filemanagerstring;
             
         } catch (Exception e) {
-            Log.e("FileDisplay", "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e);
+            Log_OC.e("FileDisplay", "Unexpected exception when trying to read the result of Intent.ACTION_GET_CONTENT", e);
             e.printStackTrace();
             
         } finally {
             if (filepath == null) {
-                Log.e("FileDisplay", "Couldnt resolve path to file");
+                Log_OC.e("FileDisplay", "Couldnt resolve path to file");
                 Toast t = Toast.makeText(this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG);
                 t.show();
                 return;
@@ -563,7 +537,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
     @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");
+        Log_OC.d(getClass().toString(), "onSaveInstanceState() start");
         super.onSaveInstanceState(outState);
         outState.putParcelable(FileDetailFragment.EXTRA_FILE, mCurrentDir);
         if (mDualPane) {
@@ -576,13 +550,13 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
             }
         }
         outState.putParcelable(FileDetailActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
-        Log.d(getClass().toString(), "onSaveInstanceState() end");
+        Log_OC.d(getClass().toString(), "onSaveInstanceState() end");
     }
 
     
     @Override
-    public void onResume() {
-        Log.d(getClass().toString(), "onResume() start");
+    protected void onResume() {
+        Log_OC.d(getClass().toString(), "onResume() start");
         super.onResume();
 
         if (AccountUtils.accountsAreSetup(this)) {
@@ -621,13 +595,13 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
             showDialog(DIALOG_SETUP_ACCOUNT);
             
         }
-        Log.d(getClass().toString(), "onResume() end");
+        Log_OC.d(getClass().toString(), "onResume() end");
     }
 
     
     @Override
-    public void onPause() {
-        Log.d(getClass().toString(), "onPause() start");
+    protected void onPause() {
+        Log_OC.d(getClass().toString(), "onPause() start");
         super.onPause();
         if (mSyncBroadcastReceiver != null) {
             unregisterReceiver(mSyncBroadcastReceiver);
@@ -645,7 +619,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
             dismissDialog(DIALOG_SETUP_ACCOUNT);
         }
         
-        Log.d(getClass().toString(), "onPause() end");
+        Log_OC.d(getClass().toString(), "onPause() end");
     }
 
     
@@ -684,22 +658,6 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
             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());
@@ -909,7 +867,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
                             msg.show();
                         
                         } catch (NotFoundException e) {
-                            Log.e(TAG, "Error while trying to show fail message " , e);
+                            Log_OC.e(TAG, "Error while trying to show fail message ", e);
                         }
                     }
                 });
@@ -952,13 +910,10 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
          */
         @Override
         public void onReceive(Context context, Intent intent) {
-            boolean inProgress = intent.getBooleanExtra(
-                    FileSyncService.IN_PROGRESS, false);
-            String accountName = intent
-                    .getStringExtra(FileSyncService.ACCOUNT_NAME);
+            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);
+            Log_OC.d("FileDisplay", "sync of account " + accountName + " is in_progress: " + inProgress);
 
             if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name)) {  
             
@@ -1252,14 +1207,14 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         @Override
         public void onServiceConnected(ComponentName component, IBinder service) {
             if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {
-                Log.d(TAG, "Download service connected");
+                Log_OC.d(TAG, "Download service connected");
                 mDownloaderBinder = (FileDownloaderBinder) service;
                 if (mWaitingToPreview != null) {
                     requestForDownload();
                 }
                 
             } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {
-                Log.d(TAG, "Upload service connected");
+                Log_OC.d(TAG, "Upload service connected");
                 mUploaderBinder = (FileUploaderBinder) service;
             } else {
                 return;
@@ -1280,10 +1235,10 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         @Override
         public void onServiceDisconnected(ComponentName component) {
             if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {
-                Log.d(TAG, "Download service disconnected");
+                Log_OC.d(TAG, "Download service disconnected");
                 mDownloaderBinder = null;
             } else if (component.equals(new ComponentName(FileDisplayActivity.this, FileUploader.class))) {
-                Log.d(TAG, "Upload service disconnected");
+                Log_OC.d(TAG, "Upload service disconnected");
                 mUploaderBinder = null;
             }
         }
index 910802f..eb0b4d5 100644 (file)
@@ -44,6 +44,7 @@ import android.widget.TextView;
 import android.widget.Toast;
 
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 import com.owncloud.android.db.DbHandler;
 import com.owncloud.android.files.InstantUploadBroadcastReceiver;
@@ -132,7 +133,7 @@ public class InstantUploadActivity extends Activity {
                     rowLayout.addView(getImageButton(imp_path, lastLoadImageIdx));
                     rowLayout.addView(getFileButton(imp_path, message, lastLoadImageIdx));
                     listView.addView(rowLayout);
-                    Log.d(LOG_TAG, imp_path + " on idx: " + lastLoadImageIdx);
+                    Log_OC.d(LOG_TAG, imp_path + " on idx: " + lastLoadImageIdx);
                     if (lastLoadImageIdx % MAX_LOAD_IMAGES == 0) {
                         break;
                     }
@@ -183,12 +184,12 @@ public class InstantUploadActivity extends Activity {
     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());
+            Log_OC.d(LOG_TAG, "ListView has Childs: " + listView.getChildCount());
             View childView = listView.getChildAt(i);
             if (childView != null && childView instanceof ViewGroup) {
                 View checkboxView = getChildViews((ViewGroup) childView);
                 if (checkboxView != null && checkboxView instanceof CheckBox) {
-                    Log.d(LOG_TAG, "found Child: " + checkboxView.getId() + " " + checkboxView.getClass());
+                    Log_OC.d(LOG_TAG, "found Child: " + checkboxView.getId() + " " + checkboxView.getClass());
                     list.add((CheckBox) checkboxView);
                 }
             }
@@ -251,12 +252,12 @@ public class InstantUploadActivity extends Activity {
                     for (CheckBox checkbox : list) {
                         boolean to_retry = checkbox.isChecked();
 
-                        Log.d(LOG_TAG, "Checkbox for " + checkbox.getId() + " was checked: " + to_retry);
+                        Log_OC.d(LOG_TAG, "Checkbox for " + checkbox.getId() + " was checked: " + to_retry);
                         String img_path = fileList.get(checkbox.getId());
                         if (to_retry) {
 
                             final String msg = "Image-Path " + checkbox.getId() + " was checked: " + img_path;
-                            Log.d(LOG_TAG, msg);
+                            Log_OC.d(LOG_TAG, msg);
                             startUpload(img_path);
                         }
 
@@ -292,12 +293,12 @@ public class InstantUploadActivity extends Activity {
                     for (CheckBox checkbox : list) {
                         boolean to_be_delete = checkbox.isChecked();
 
-                        Log.d(LOG_TAG, "Checkbox for " + checkbox.getId() + " was checked: " + to_be_delete);
+                        Log_OC.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);
+                        Log_OC.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);
+                            Log_OC.d(LOG_TAG, "removing " + checkbox.getId() + " was : " + deleted);
 
                         }
 
@@ -391,7 +392,7 @@ public class InstantUploadActivity extends Activity {
         // 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");
+            Log_OC.d(LOG_TAG, "add " + img_path + " to Image Button");
             BitmapFactory.Options options = new BitmapFactory.Options();
             options.inJustDecodeBounds = true;
             Bitmap bitmap = BitmapFactory.decodeFile(img_path, options);
@@ -406,16 +407,16 @@ public class InstantUploadActivity extends Activity {
                 scale++;
             }
 
-            Log.d(LOG_TAG, "scale Imgae with: " + scale);
+            Log_OC.d(LOG_TAG, "scale Imgae with: " + scale);
             BitmapFactory.Options options2 = new BitmapFactory.Options();
             options2.inSampleSize = scale;
             bitmap = BitmapFactory.decodeFile(img_path, options2);
 
             if (bitmap != null) {
-                Log.d(LOG_TAG, "loaded Bitmap Bytes: " + bitmap.getRowBytes());
+                Log_OC.d(LOG_TAG, "loaded Bitmap Bytes: " + bitmap.getRowBytes());
                 imageButton.setImageBitmap(bitmap);
             } else {
-                Log.d(LOG_TAG, "could not load imgage: " + img_path);
+                Log_OC.d(LOG_TAG, "could not load imgage: " + img_path);
             }
         }
         return imageButton;
@@ -459,7 +460,7 @@ public class InstantUploadActivity extends Activity {
             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);
+            Log_OC.d(LOG_TAG, msg);
             Toast toast = Toast.makeText(InstantUploadActivity.this, getString(R.string.failed_upload_retry_text)
                     + filename, Toast.LENGTH_LONG);
             toast.show();
diff --git a/src/com/owncloud/android/ui/activity/LogHistoryActivity.java b/src/com/owncloud/android/ui/activity/LogHistoryActivity.java
new file mode 100644 (file)
index 0000000..dd068c7
--- /dev/null
@@ -0,0 +1,119 @@
+/* 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 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 java.util.ArrayList;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Environment;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ListView;
+
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.SherlockPreferenceActivity;
+import com.actionbarsherlock.view.MenuItem;
+import com.owncloud.android.R;
+import com.owncloud.android.ui.adapter.LogListAdapter;
+
+
+
+public class LogHistoryActivity extends SherlockPreferenceActivity implements OnPreferenceChangeListener {
+    String logpath = Environment.getExternalStorageDirectory()+File.separator+"owncloud"+File.separator+"log";
+    File logDIR = null;
+    
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        
+        setContentView(R.layout.log_send_file);
+        setTitle("Log History");
+        ActionBar actionBar = getSherlock().getActionBar();
+        actionBar.setDisplayHomeAsUpEnabled(true);
+        ListView listView = (ListView) findViewById(android.R.id.list);
+        Button deleteHistoryButton = (Button) findViewById(R.id.deleteLogHistoryButton);
+        deleteHistoryButton.setOnClickListener(new OnClickListener() {
+            
+            @Override
+            public void onClick(View v) {
+                File dir = new File(logpath);
+                if (dir != null) {
+                    File[] files = dir.listFiles();
+                    if(files!=null) { 
+                        for(File f: files) {
+                                f.delete();
+                        }
+                    }
+                    dir.delete();
+                }
+                Intent intent = new Intent(getBaseContext(), Preferences.class);
+                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                startActivity(intent);
+            }
+            
+        });
+        
+       
+        if(logpath != null){
+        logDIR = new File(logpath);
+        }
+        
+        if(logDIR != null && logDIR.isDirectory()) {
+            File[] files = logDIR.listFiles();
+          
+            if (files != null && files.length != 0) {
+                ArrayList<String> logfiles_name = new ArrayList<String>();
+                for (File file : files) {
+                    logfiles_name.add(file.getName());
+                }
+                    String[] logFiles2Array = logfiles_name.toArray(new String[logfiles_name.size()]);
+                    LogListAdapter listadapter = new LogListAdapter(this,logFiles2Array);
+                    listView.setAdapter(listadapter);
+            }
+        }
+    }
+
+    
+    @Override
+    public boolean onMenuItemSelected(int featureId, MenuItem item) {
+        super.onMenuItemSelected(featureId, item);
+        Intent intent;
+
+        switch (item.getItemId()) {
+       
+        case android.R.id.home:
+            intent = new Intent(getBaseContext(), Preferences.class);
+            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            startActivity(intent);
+            break;
+        default:
+            return false;
+        }
+        return true;
+    }
+    @Override
+    public boolean onPreferenceChange(Preference arg0, Object arg1) {
+        return false;
+    }
+}
\ No newline at end of file
index 460c5e0..1f9632c 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
-package com.owncloud.android.ui.activity;\r
-\r
-import java.util.Vector;\r
-\r
-import android.content.Intent;\r
-import android.content.SharedPreferences;\r
-import android.os.Bundle;\r
-import android.preference.CheckBoxPreference;\r
-import android.preference.ListPreference;\r
-import android.preference.Preference;\r
-import android.preference.PreferenceManager;\r
-import android.preference.Preference.OnPreferenceChangeListener;\r
-import android.preference.Preference.OnPreferenceClickListener;\r
-import android.util.Log;\r
-\r
-import com.actionbarsherlock.app.ActionBar;\r
-import com.actionbarsherlock.app.SherlockPreferenceActivity;\r
-import com.actionbarsherlock.view.Menu;\r
-import com.actionbarsherlock.view.MenuItem;\r
-import com.owncloud.android.OwnCloudSession;\r
-import com.owncloud.android.db.DbHandler;\r
-\r
-import com.owncloud.android.R;\r
-\r
-/**\r
- * An Activity that allows the user to change the application's settings.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
- */\r
-public class Preferences extends SherlockPreferenceActivity implements\r
-        OnPreferenceChangeListener{\r
-    private static final String TAG = "OwnCloudPreferences";\r
-    private final int mNewSession = 47;\r
-    private final int mEditSession = 48;\r
-    private DbHandler mDbHandler;\r
-    private Vector<OwnCloudSession> mSessions;\r
-    //private Account[] mAccounts;\r
-    //private ListPreference mAccountList;\r
-    private ListPreference mTrackingUpdateInterval;\r
-    private CheckBoxPreference mDeviceTracking;\r
-    private CheckBoxPreference pCode;\r
-    private int mSelectedMenuItem;\r
-\r
-    @Override\r
-    public void onCreate(Bundle savedInstanceState) {\r
-        super.onCreate(savedInstanceState);\r
-        mDbHandler = new DbHandler(getBaseContext());\r
-        mSessions = new Vector<OwnCloudSession>();\r
-        addPreferencesFromResource(R.xml.preferences);\r
-        //populateAccountList();\r
-        ActionBar actionBar = getSherlock().getActionBar();\r
-        actionBar.setDisplayHomeAsUpEnabled(true);\r
-        Preference p = findPreference("manage_account");\r
-        if (p != null)\r
-        p.setOnPreferenceClickListener(new OnPreferenceClickListener() {\r
-            @Override\r
-            public boolean onPreferenceClick(Preference preference) {\r
-                Intent i = new Intent(getApplicationContext(), AccountSelectActivity.class);\r
-                startActivity(i);\r
-                return true;\r
-            }\r
-        });\r
-        \r
-        pCode = (CheckBoxPreference) findPreference("set_pincode");\r
-         \r
-        \r
-        if (pCode != null){\r
-            \r
-            pCode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {\r
-                @Override\r
-                public boolean onPreferenceChange(Preference preference, Object newValue) {\r
-                                          \r
-                    Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);\r
-                    i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "preferences");\r
-                    i.putExtra(PinCodeActivity.EXTRA_NEW_STATE, newValue.toString());\r
-                    \r
-                    startActivity(i);\r
-                    \r
-                    return true;\r
-                }\r
-            });            \r
-            \r
-        }\r
-        \r
-    }\r
-\r
-\r
-    @Override\r
-    protected void onResume() {\r
-        // TODO Auto-generated method stub\r
-        SharedPreferences appPrefs = PreferenceManager\r
-                .getDefaultSharedPreferences(getApplicationContext());\r
-        \r
-        boolean state = appPrefs.getBoolean("set_pincode", false);\r
-        pCode.setChecked(state);\r
-        \r
-        super.onResume();\r
-    }\r
-\r
-\r
-\r
-    /**\r
-     * Populates the account selector\r
-     *-/\r
-    private void populateAccountList() {\r
-        AccountManager accMan = AccountManager.get(this);\r
-        mAccounts = accMan.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);\r
-        mAccountList = (ListPreference) findPreference("select_oc_account");\r
-        mAccountList.setOnPreferenceChangeListener(this);\r
-\r
-        // Display the name of the current account if there is any\r
-        Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this);\r
-        if (defaultAccount != null) {\r
-            mAccountList.setSummary(defaultAccount.name);\r
-        }\r
-        \r
-        // Transform accounts into array of string for preferences to use\r
-        String[] accNames = new String[mAccounts.length];\r
-        for (int i = 0; i < mAccounts.length; i++) {\r
-            Account account = mAccounts[i];\r
-            accNames[i] = account.name;\r
-        }\r
-\r
-        mAccountList.setEntries(accNames);\r
-        mAccountList.setEntryValues(accNames);\r
-    }*/\r
-\r
-    \r
-    \r
-    @Override\r
-    public boolean onCreateOptionsMenu(Menu menu) {\r
-        super.onCreateOptionsMenu(menu);\r
-        //MenuInflater inflater = getSherlock().getMenuInflater();\r
-        //inflater.inflate(R.menu.prefs_menu, menu);\r
-        return true;\r
-    }\r
-\r
-    @Override\r
-    public boolean onMenuItemSelected(int featureId, MenuItem item) {\r
-        super.onMenuItemSelected(featureId, item);\r
-        Intent intent;\r
-\r
-        switch (item.getItemId()) {\r
-        //case R.id.addSessionItem:\r
-        case 1:\r
-            intent = new Intent(this, PreferencesNewSession.class);\r
-            startActivityForResult(intent, mNewSession);\r
-            break;\r
-        case R.id.SessionContextEdit:\r
-            intent = new Intent(this, PreferencesNewSession.class);\r
-            intent.putExtra("sessionId", mSessions.get(mSelectedMenuItem)\r
-                    .getEntryId());\r
-            intent.putExtra("sessionName", mSessions.get(mSelectedMenuItem)\r
-                    .getName());\r
-            intent.putExtra("sessionURL", mSessions.get(mSelectedMenuItem)\r
-                    .getUrl());\r
-            startActivityForResult(intent, mEditSession);\r
-            break;\r
-        case android.R.id.home:\r
-            intent = new Intent(getBaseContext(), FileDisplayActivity.class);\r
-            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
-            startActivity(intent);\r
-            break;\r
-        default:\r
-            Log.w(TAG, "Unknown menu item triggered");\r
-            return false;\r
-        }\r
-        return true;\r
-    }\r
-\r
-    @Override\r
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\r
-        super.onActivityResult(requestCode, resultCode, data);\r
-    }\r
-\r
-    @Override\r
-    protected void onDestroy() {\r
-        mDbHandler.close();\r
-        super.onDestroy();\r
-    }\r
-\r
-    \r
-    \r
-    @Override\r
-    /**\r
-     * Updates various summaries after updates. Also starts and stops \r
-     * the\r
-     */\r
-    public boolean onPreferenceChange(Preference preference, Object newValue) {\r
-        // Update current account summary\r
-        /*if (preference.equals(mAccountList)) {\r
-            mAccountList.setSummary(newValue.toString());\r
-        }\r
-\r
-        // Update tracking interval summary\r
-        else*/ if (preference.equals(mTrackingUpdateInterval)) {\r
-            String trackingSummary = getResources().getString(\r
-                    R.string.prefs_trackmydevice_interval_summary);\r
-            trackingSummary = String.format(trackingSummary,\r
-                    newValue.toString());\r
-            mTrackingUpdateInterval.setSummary(trackingSummary);\r
-        }\r
-\r
-        // Start or stop tracking service\r
-        else if (preference.equals(mDeviceTracking)) {\r
-            Intent locationServiceIntent = new Intent();\r
-            locationServiceIntent\r
-                    .setAction("com.owncloud.android.location.LocationLauncher");\r
-            locationServiceIntent.putExtra("TRACKING_SETTING",\r
-                    (Boolean) newValue);\r
-            sendBroadcast(locationServiceIntent);\r
-        } \r
-        return true;\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 java.util.Vector;
+
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.os.Environment;
+import android.preference.CheckBoxPreference;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.SherlockPreferenceActivity;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.OwnCloudSession;
+import com.owncloud.android.R;
+import com.owncloud.android.db.DbHandler;
+
+/**
+ * An Activity that allows the user to change the application's settings.
+ * 
+ * @author Bartek Przybylski
+ * 
+ */
+public class Preferences extends SherlockPreferenceActivity implements OnPreferenceChangeListener {
+    
+    private static final String TAG = "OwnCloudPreferences";
+    private final int mNewSession = 47;
+    private final int mEditSession = 48;
+    private DbHandler mDbHandler;
+    private Vector<OwnCloudSession> mSessions;
+    private ListPreference mTrackingUpdateInterval;
+    private CheckBoxPreference mDeviceTracking;
+    private CheckBoxPreference pCode;
+    private CheckBoxPreference pLogging;
+    private Preference pLoggingHistory;
+    private Preference pAboutApp;
+    private int mSelectedMenuItem;
+
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mDbHandler = new DbHandler(getBaseContext());
+        mSessions = new Vector<OwnCloudSession>();
+        addPreferencesFromResource(R.xml.preferences);
+        //populateAccountList();
+        ActionBar actionBar = getSherlock().getActionBar();
+        actionBar.setDisplayHomeAsUpEnabled(true);
+        Preference p = findPreference("manage_account");
+        if (p != null)
+        p.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+            @Override
+            public boolean onPreferenceClick(Preference preference) {
+                Intent i = new Intent(getApplicationContext(), AccountSelectActivity.class);
+                startActivity(i);
+                return true;
+            }
+        });
+        
+        pCode = (CheckBoxPreference) findPreference("set_pincode");
+        if (pCode != null){
+            pCode.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+                @Override
+                public boolean onPreferenceChange(Preference preference, Object newValue) {
+                    Intent i = new Intent(getApplicationContext(), PinCodeActivity.class);
+                    i.putExtra(PinCodeActivity.EXTRA_ACTIVITY, "preferences");
+                    i.putExtra(PinCodeActivity.EXTRA_NEW_STATE, newValue.toString());
+                    startActivity(i);
+                    return true;
+                }
+            });
+            
+           /* About App */
+       pAboutApp = (Preference) findPreference("about_app");
+       if (pAboutApp != null) { 
+               pAboutApp.setTitle(getString(R.string.app_name)+" "+getString(R.string.about_android));
+               PackageInfo pkg;
+               try {
+                   pkg = getPackageManager().getPackageInfo(getPackageName(), 0);
+                   pAboutApp.setSummary(getString(R.string.about_version)+" "+pkg.versionName);
+               } catch (NameNotFoundException e) {
+                   Log_OC.e(TAG, "Error while showing about dialog", e);
+               }
+       }
+       
+       pLogging = (CheckBoxPreference) findPreference("log_to_file");
+       if (pLogging != null) {
+           pLogging.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+               @Override
+               public boolean onPreferenceChange(Preference preference, Object newValue) {
+                   
+                   String logpath = Environment.getExternalStorageDirectory()+File.separator+"owncloud"+File.separator+"log";
+                
+                   if(!pLogging.isChecked()) {
+                       Log_OC.d("Debug", "start logging");
+                       Log_OC.v("PATH", logpath);
+                       Log_OC.startLogging(logpath);
+                   }
+                   else {
+                       Log_OC.d("Debug", "stop logging");
+                       Log_OC.stopLogging();
+                   }
+                   return true;
+               }
+           });
+       }
+       
+       pLoggingHistory = (Preference) findPreference("log_history");
+       if (pLoggingHistory != null) {
+           pLoggingHistory.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+            
+            @Override
+            public boolean onPreferenceClick(Preference preference) {
+                Intent intent = new Intent(getApplicationContext(),LogHistoryActivity.class);
+                startActivity(intent);
+                return true;
+            }
+        });
+       }
+      }
+    }
+
+    @Override
+    protected void onResume() {
+        SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+        boolean state = appPrefs.getBoolean("set_pincode", false);
+        pCode.setChecked(state);
+        super.onResume();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        super.onCreateOptionsMenu(menu);
+        return true;
+    }
+
+    @Override
+    public boolean onMenuItemSelected(int featureId, MenuItem item) {
+        super.onMenuItemSelected(featureId, item);
+        Intent intent;
+
+        switch (item.getItemId()) {
+        //case R.id.addSessionItem:
+        case 1:
+            intent = new Intent(this, PreferencesNewSession.class);
+            startActivityForResult(intent, mNewSession);
+            break;
+        case R.id.SessionContextEdit:
+            intent = new Intent(this, PreferencesNewSession.class);
+            intent.putExtra("sessionId", mSessions.get(mSelectedMenuItem)
+                    .getEntryId());
+            intent.putExtra("sessionName", mSessions.get(mSelectedMenuItem)
+                    .getName());
+            intent.putExtra("sessionURL", mSessions.get(mSelectedMenuItem)
+                    .getUrl());
+            startActivityForResult(intent, mEditSession);
+            break;
+        case android.R.id.home:
+            intent = new Intent(getBaseContext(), FileDisplayActivity.class);
+            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            startActivity(intent);
+            break;
+        default:
+            Log_OC.w(TAG, "Unknown menu item triggered");
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+    }
+
+    @Override
+    protected void onDestroy() {
+        mDbHandler.close();
+        super.onDestroy();
+    }
+    
+    @Override
+    /**
+     * Updates various summaries after updates. Also starts and stops 
+     * the
+     */
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        // Update current account summary
+        /*if (preference.equals(mAccountList)) {
+            mAccountList.setSummary(newValue.toString());
+        }
+
+        // Update tracking interval summary
+        else*/ if (preference.equals(mTrackingUpdateInterval)) {
+            String trackingSummary = getResources().getString(
+                    R.string.prefs_trackmydevice_interval_summary);
+            trackingSummary = String.format(trackingSummary,
+                    newValue.toString());
+            mTrackingUpdateInterval.setSummary(trackingSummary);
+        }
+
+        // Start or stop tracking service
+        else if (preference.equals(mDeviceTracking)) {
+            Intent locationServiceIntent = new Intent();
+            locationServiceIntent
+                    .setAction("com.owncloud.android.location.LocationLauncher");
+            locationServiceIntent.putExtra("TRACKING_SETTING",
+                    (Boolean) newValue);
+            sendBroadcast(locationServiceIntent);
+        } 
+        return true;
+    }
+}
index d16b263..4b28ac1 100644 (file)
@@ -44,6 +44,7 @@ import com.owncloud.android.ui.fragment.LocalFileListFragment;
 import com.owncloud.android.ui.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
 import com.owncloud.android.utils.FileStorageUtils;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 
 /**
@@ -78,7 +79,7 @@ public class UploadFilesActivity extends SherlockFragmentActivity implements
     
     @Override
     public void onCreate(Bundle savedInstanceState) {
-        Log.d(TAG, "onCreate() start");
+        Log_OC.d(TAG, "onCreate() start");
         super.onCreate(savedInstanceState);
 
         if(savedInstanceState != null) {
@@ -125,7 +126,7 @@ public class UploadFilesActivity extends SherlockFragmentActivity implements
             mCurrentDialog = null;
         }
             
-        Log.d(TAG, "onCreate() end");
+        Log_OC.d(TAG, "onCreate() end");
     }
 
 
@@ -181,10 +182,10 @@ public class UploadFilesActivity extends SherlockFragmentActivity implements
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved
-        Log.d(TAG, "onSaveInstanceState() start");
+        Log_OC.d(TAG, "onSaveInstanceState() start");
         super.onSaveInstanceState(outState);
         outState.putString(UploadFilesActivity.KEY_DIRECTORY_PATH, mCurrentDir.getAbsolutePath());
-        Log.d(TAG, "onSaveInstanceState() end");
+        Log_OC.d(TAG, "onSaveInstanceState() end");
     }
 
     
@@ -354,7 +355,7 @@ public class UploadFilesActivity extends SherlockFragmentActivity implements
 
     @Override
     public void onConfirmation(String callerTag) {
-        Log.d(TAG, "Positive button in dialog was clicked; dialog tag is " + callerTag);
+        Log_OC.d(TAG, "Positive button in dialog was clicked; dialog tag is " + callerTag);
         if (callerTag.equals(QUERY_TO_MOVE_DIALOG_TAG)) {
             // return the list of selected files to the caller activity (success), signaling that they should be moved to the ownCloud folder, instead of copied
             Intent data = new Intent();
@@ -367,14 +368,14 @@ public class UploadFilesActivity extends SherlockFragmentActivity implements
 
     @Override
     public void onNeutral(String callerTag) {
-        Log.d(TAG, "Phantom neutral button in dialog was clicked; dialog tag is " + callerTag);
+        Log_OC.d(TAG, "Phantom neutral button in dialog was clicked; dialog tag is " + callerTag);
     }
 
 
     @Override
     public void onCancel(String callerTag) {
         /// nothing to do; don't finish, let the user change the selection
-        Log.d(TAG, "Negative button in dialog was clicked; dialog tag is " + callerTag);
+        Log_OC.d(TAG, "Negative button in dialog was clicked; dialog tag is " + callerTag);
     }    
 
     
diff --git a/src/com/owncloud/android/ui/adapter/LogListAdapter.java b/src/com/owncloud/android/ui/adapter/LogListAdapter.java
new file mode 100644 (file)
index 0000000..6b6e8f6
--- /dev/null
@@ -0,0 +1,54 @@
+package com.owncloud.android.ui.adapter;
+
+import java.io.File;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Environment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import com.owncloud.android.R;
+
+
+public class LogListAdapter extends ArrayAdapter<String> {
+    private Context context = null;
+    private String[] values;
+    private Uri fileUri = null;
+   
+    
+    public LogListAdapter(Context context, String[] values) {
+        super(context, R.layout.log_item, values);
+        this.context = context;
+        this.values = values;
+    }
+
+    @Override
+    public View getView(final int position, View convertView, ViewGroup parent) {
+        LayoutInflater inflater = (LayoutInflater) context
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        View rowView = inflater.inflate(R.layout.log_item, parent, false);
+        TextView listText = (TextView) rowView.findViewById(R.id.log_item_single);
+        listText.setText(values[position]);
+        listText.setTextSize(15);
+        fileUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory()+File.separator+"owncloud"+File.separator+"log"+File.separator+values[position]));
+        listText.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
+                emailIntent.setType("text/rtf");
+                emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "OwnCloud Logfile");
+                emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, "This is a automatic E-mail send by owncloud/android");
+                emailIntent.putExtra(android.content.Intent.EXTRA_STREAM, fileUri);
+                emailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                context.startActivity(Intent.createChooser(emailIntent, "Send mail..."));
+            }
+        });
+        return rowView;
+    }
+}
index 2143e9a..201fd7e 100644 (file)
@@ -38,6 +38,7 @@ import android.view.Window;
 import android.widget.Button;
 import android.widget.TextView;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 import com.owncloud.android.network.CertificateCombinedException;
 import com.owncloud.android.network.OwnCloudClientUtils;
@@ -110,13 +111,13 @@ public class SslValidatorDialog extends Dialog {
                             if (mListener != null)
                                 mListener.onSavedCertificate();
                             else
-                                Log.d(TAG, "Nobody there to notify the certificate was saved");
+                                Log_OC.d(TAG, "Nobody there to notify the certificate was saved");
                             
                         } catch (Exception e) {
                             dismiss();
                             if (mListener != null)
                                 mListener.onFailedSavingCertificate();
-                            Log.e(TAG, "Server certificate could not be saved in the known servers trust store ", e);
+                            Log_OC.e(TAG, "Server certificate could not be saved in the known servers trust store ", e);
                         }
                     }
                 });
index 7a59bd6..7db3641 100644 (file)
@@ -26,6 +26,7 @@ import android.os.Bundle;
 import android.util.Log;
 
 import com.actionbarsherlock.app.SherlockDialogFragment;
+import com.owncloud.android.Log_OC;
 
 public class ConfirmationDialogFragment extends SherlockDialogFragment {
 
@@ -75,7 +76,7 @@ public class ConfirmationDialogFragment extends SherlockDialogFragment {
         int negBtn = getArguments().getInt(ARG_NEGATIVE_BTN_RES, -1);
         
         if (confirmationTarget == null || resourceId == -1) {
-            Log.wtf(getTag(), "Calling confirmation dialog without resource or arguments");
+            Log_OC.wtf(getTag(), "Calling confirmation dialog without resource or arguments");
             return null;
         }
 
index 80dc426..96218a6 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
-package com.owncloud.android.ui.fragment;\r
-\r
-import java.io.File;\r
-import java.lang.ref.WeakReference;\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-\r
-import org.apache.commons.httpclient.methods.GetMethod;\r
-import org.apache.commons.httpclient.methods.PostMethod;\r
-import org.apache.commons.httpclient.methods.StringRequestEntity;\r
-import org.apache.commons.httpclient.params.HttpConnectionManagerParams;\r
-import org.apache.http.HttpStatus;\r
-import org.apache.http.NameValuePair;\r
-import org.apache.http.client.utils.URLEncodedUtils;\r
-import org.apache.http.message.BasicNameValuePair;\r
-import org.apache.http.protocol.HTTP;\r
-import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;\r
-import org.json.JSONObject;\r
-\r
-import android.accounts.Account;\r
-import android.accounts.AccountManager;\r
-import android.app.Activity;\r
-import android.content.ActivityNotFoundException;\r
-import android.content.BroadcastReceiver;\r
-import android.content.Context;\r
-import android.content.Intent;\r
-import android.content.IntentFilter;\r
-import android.net.Uri;\r
-import android.os.Bundle;\r
-import android.os.Handler;\r
-import android.support.v4.app.FragmentTransaction;\r
-import android.util.Log;\r
-import android.view.LayoutInflater;\r
-import android.view.View;\r
-import android.view.View.OnClickListener;\r
-import android.view.ViewGroup;\r
-import android.webkit.MimeTypeMap;\r
-import android.widget.Button;\r
-import android.widget.CheckBox;\r
-import android.widget.ImageView;\r
-import android.widget.ProgressBar;\r
-import android.widget.TextView;\r
-import android.widget.Toast;\r
-\r
-import com.actionbarsherlock.app.SherlockFragment;\r
-import com.owncloud.android.AccountUtils;\r
-import com.owncloud.android.DisplayUtils;\r
-import com.owncloud.android.authenticator.AccountAuthenticator;\r
-import com.owncloud.android.datamodel.FileDataStorageManager;\r
-import com.owncloud.android.datamodel.OCFile;\r
-import com.owncloud.android.files.services.FileObserverService;\r
-import com.owncloud.android.files.services.FileUploader;\r
-import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;\r
-import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;\r
-import com.owncloud.android.network.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.RemoteOperationResult.ResultCode;\r
-import com.owncloud.android.operations.RemoveFileOperation;\r
-import com.owncloud.android.operations.RenameFileOperation;\r
-import com.owncloud.android.operations.SynchronizeFileOperation;\r
-import com.owncloud.android.ui.activity.ConflictsResolveActivity;\r
-import com.owncloud.android.ui.activity.FileDetailActivity;\r
-import com.owncloud.android.ui.activity.FileDisplayActivity;\r
-import com.owncloud.android.ui.dialog.EditNameDialog;\r
-import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;\r
-import com.owncloud.android.utils.OwnCloudVersion;\r
-\r
-import com.owncloud.android.R;\r
-\r
-import eu.alefzero.webdav.OnDatatransferProgressListener;\r
-import eu.alefzero.webdav.WebdavClient;\r
-import eu.alefzero.webdav.WebdavUtils;\r
-\r
-/**\r
- * This Fragment is used to display the details about a file.\r
- * \r
- * @author Bartek Przybylski\r
- * @author David A. Velasco\r
- */\r
-public class FileDetailFragment extends SherlockFragment implements\r
-        OnClickListener, \r
-        ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener, EditNameDialogListener,\r
-        FileFragment {\r
-\r
-    public static final String EXTRA_FILE = "FILE";\r
-    public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
-\r
-    private FileFragment.ContainerActivity mContainerActivity;\r
-    \r
-    private int mLayout;\r
-    private View mView;\r
-    private OCFile mFile;\r
-    private Account mAccount;\r
-    private FileDataStorageManager mStorageManager;\r
-    \r
-    private UploadFinishReceiver mUploadFinishReceiver;\r
-    public ProgressListener mProgressListener;\r
-    \r
-    private Handler mHandler;\r
-    private RemoteOperation mLastRemoteOperation;\r
-    \r
-    private static final String TAG = FileDetailFragment.class.getSimpleName();\r
-    public static final String FTAG = "FileDetails"; \r
-    public static final String FTAG_CONFIRMATION = "REMOVE_CONFIRMATION_FRAGMENT";\r
-\r
-    \r
-    /**\r
-     * Creates an empty details fragment.\r
-     * \r
-     * It's necessary to keep a public constructor without parameters; the system uses it when tries to reinstantiate a fragment automatically. \r
-     */\r
-    public FileDetailFragment() {\r
-        mFile = null;\r
-        mAccount = null;\r
-        mStorageManager = null;\r
-        mLayout = R.layout.file_details_empty;\r
-        mProgressListener = null;\r
-    }\r
-    \r
-    \r
-    /**\r
-     * Creates a details fragment.\r
-     * \r
-     * When 'fileToDetail' or 'ocAccount' are null, creates a dummy layout (to use when a file wasn't tapped before).\r
-     * \r
-     * @param fileToDetail      An {@link OCFile} to show in the fragment\r
-     * @param ocAccount         An ownCloud account; needed to start downloads\r
-     */\r
-    public FileDetailFragment(OCFile fileToDetail, Account ocAccount) {\r
-        mFile = fileToDetail;\r
-        mAccount = ocAccount;\r
-        mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment \r
-        mLayout = R.layout.file_details_empty;\r
-        mProgressListener = null;\r
-    }\r
-    \r
-    \r
-    @Override\r
-    public void onCreate(Bundle savedInstanceState) {\r
-        super.onCreate(savedInstanceState);\r
-        mHandler = new Handler();\r
-    }\r
-    \r
-\r
-    @Override\r
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
-            Bundle savedInstanceState) {\r
-        super.onCreateView(inflater, container, savedInstanceState);\r
-        \r
-        if (savedInstanceState != null) {\r
-            mFile = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE);\r
-            mAccount = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_ACCOUNT);\r
-        }\r
-        \r
-        if(mFile != null && mAccount != null) {\r
-            mLayout = R.layout.file_details_fragment;\r
-        }\r
-        \r
-        View view = null;\r
-        view = inflater.inflate(mLayout, container, false);\r
-        mView = view;\r
-        \r
-        if (mLayout == R.layout.file_details_fragment) {\r
-            mView.findViewById(R.id.fdKeepInSync).setOnClickListener(this);\r
-            mView.findViewById(R.id.fdRenameBtn).setOnClickListener(this);\r
-            mView.findViewById(R.id.fdDownloadBtn).setOnClickListener(this);\r
-            mView.findViewById(R.id.fdOpenBtn).setOnClickListener(this);\r
-            mView.findViewById(R.id.fdRemoveBtn).setOnClickListener(this);\r
-            //mView.findViewById(R.id.fdShareBtn).setOnClickListener(this);\r
-            ProgressBar progressBar = (ProgressBar)mView.findViewById(R.id.fdProgressBar);\r
-            mProgressListener = new ProgressListener(progressBar);\r
-        }\r
-        \r
-        updateFileDetails(false, false);\r
-        return view;\r
-    }\r
-    \r
-\r
-    /**\r
-     * {@inheritDoc}\r
-     */\r
-    @Override\r
-    public void onAttach(Activity activity) {\r
-        super.onAttach(activity);\r
-        try {\r
-            mContainerActivity = (ContainerActivity) activity;\r
-            \r
-        } catch (ClassCastException e) {\r
-            throw new ClassCastException(activity.toString() + " must implement " + FileDetailFragment.ContainerActivity.class.getSimpleName());\r
-        }\r
-    }\r
-    \r
-    \r
-    /**\r
-     * {@inheritDoc}\r
-     */\r
-    @Override\r
-    public void onActivityCreated(Bundle savedInstanceState) {\r
-        super.onActivityCreated(savedInstanceState);\r
-        if (mAccount != null) {\r
-            mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());\r
-        }\r
-    }\r
-        \r
-\r
-    @Override\r
-    public void onSaveInstanceState(Bundle outState) {\r
-        super.onSaveInstanceState(outState);\r
-        outState.putParcelable(FileDetailFragment.EXTRA_FILE, mFile);\r
-        outState.putParcelable(FileDetailFragment.EXTRA_ACCOUNT, mAccount);\r
-    }\r
-\r
-    @Override\r
-    public void onStart() {\r
-        super.onStart();\r
-        listenForTransferProgress();\r
-    }\r
-    \r
-    @Override\r
-    public void onResume() {\r
-        super.onResume();\r
-        mUploadFinishReceiver = new UploadFinishReceiver();\r
-        IntentFilter filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);\r
-        getActivity().registerReceiver(mUploadFinishReceiver, filter);\r
-\r
-    }\r
-\r
-\r
-    @Override\r
-    public void onPause() {\r
-        super.onPause();\r
-        if (mUploadFinishReceiver != null) {\r
-            getActivity().unregisterReceiver(mUploadFinishReceiver);\r
-            mUploadFinishReceiver = null;\r
-        }\r
-    }\r
-\r
-    \r
-    @Override\r
-    public void onStop() {\r
-        super.onStop();\r
-        leaveTransferProgress();\r
-    }\r
-\r
-    \r
-    @Override\r
-    public View getView() {\r
-        return super.getView() == null ? mView : super.getView();\r
-    }\r
-\r
-    \r
-    @Override\r
-    public void onClick(View v) {\r
-        switch (v.getId()) {\r
-            case R.id.fdDownloadBtn: {\r
-                FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();\r
-                FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();\r
-                if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {\r
-                    downloaderBinder.cancel(mAccount, mFile);\r
-                    if (mFile.isDown()) {\r
-                        setButtonsForDown();\r
-                    } else {\r
-                        setButtonsForRemote();\r
-                    }\r
-\r
-                } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile)) {\r
-                    uploaderBinder.cancel(mAccount, mFile);\r
-                    if (!mFile.fileExists()) {\r
-                        // TODO make something better\r
-                        if (getActivity() instanceof FileDisplayActivity) {\r
-                            // double pane\r
-                            FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();\r
-                            transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FTAG); // empty FileDetailFragment\r
-                            transaction.commit();\r
-                            mContainerActivity.onFileStateChanged();\r
-                        } else {\r
-                            getActivity().finish();\r
-                        }\r
-                        \r
-                    } else if (mFile.isDown()) {\r
-                        setButtonsForDown();\r
-                    } else {\r
-                        setButtonsForRemote();\r
-                    }\r
-                    \r
-                } else {\r
-                    mLastRemoteOperation = new SynchronizeFileOperation(mFile, null, mStorageManager, mAccount, true, false, getActivity());\r
-                    WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());\r
-                    mLastRemoteOperation.execute(wc, this, mHandler);\r
-                \r
-                    // update ui \r
-                    boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
-                    getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
-                    \r
-                }\r
-                break;\r
-            }\r
-            case R.id.fdKeepInSync: {\r
-                CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync);\r
-                mFile.setKeepInSync(cb.isChecked());\r
-                mStorageManager.saveFile(mFile);\r
-                \r
-                /// register the OCFile instance in the observer service to monitor local updates;\r
-                /// if necessary, the file is download \r
-                Intent intent = new Intent(getActivity().getApplicationContext(),\r
-                                           FileObserverService.class);\r
-                intent.putExtra(FileObserverService.KEY_FILE_CMD,\r
-                           (cb.isChecked()?\r
-                                   FileObserverService.CMD_ADD_OBSERVED_FILE:\r
-                                   FileObserverService.CMD_DEL_OBSERVED_FILE));\r
-                intent.putExtra(FileObserverService.KEY_CMD_ARG_FILE, mFile);\r
-                intent.putExtra(FileObserverService.KEY_CMD_ARG_ACCOUNT, mAccount);\r
-                getActivity().startService(intent);\r
-                \r
-                if (mFile.keepInSync()) {\r
-                    onClick(getView().findViewById(R.id.fdDownloadBtn));    // force an immediate synchronization\r
-                }\r
-                break;\r
-            }\r
-            case R.id.fdRenameBtn: {\r
-                EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), mFile.getFileName(), this);\r
-                dialog.show(getFragmentManager(), "nameeditdialog");\r
-                break;\r
-            }   \r
-            case R.id.fdRemoveBtn: {\r
-                ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(\r
-                        R.string.confirmation_remove_alert,\r
-                        new String[]{mFile.getFileName()},\r
-                        mFile.isDown() ? R.string.confirmation_remove_remote_and_local : R.string.confirmation_remove_remote,\r
-                        mFile.isDown() ? R.string.confirmation_remove_local : -1,\r
-                        R.string.common_cancel);\r
-                confDialog.setOnConfirmationListener(this);\r
-                confDialog.show(getFragmentManager(), FTAG_CONFIRMATION);\r
-                break;\r
-            }\r
-            case R.id.fdOpenBtn: {\r
-                openFile();\r
-                break;\r
-            }\r
-            default:\r
-                Log.e(TAG, "Incorrect view clicked!");\r
-        }\r
-        \r
-        /* else if (v.getId() == R.id.fdShareBtn) {\r
-            Thread t = new Thread(new ShareRunnable(mFile.getRemotePath()));\r
-            t.start();\r
-        }*/\r
-    }\r
-    \r
-    \r
-    /**\r
-     * Opens mFile.\r
-     */\r
-    private void openFile() {\r
-        \r
-        String storagePath = mFile.getStoragePath();\r
-        String encodedStoragePath = WebdavUtils.encodePath(storagePath);\r
-        try {\r
-            Intent i = new Intent(Intent.ACTION_VIEW);\r
-            i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype());\r
-            i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\r
-            startActivity(i);\r
-            \r
-        } catch (Throwable t) {\r
-            Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());\r
-            boolean toastIt = true; \r
-            String mimeType = "";\r
-            try {\r
-                Intent i = new Intent(Intent.ACTION_VIEW);\r
-                mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));\r
-                if (mimeType == null || !mimeType.equals(mFile.getMimetype())) {\r
-                    if (mimeType != null) {\r
-                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);\r
-                    } else {\r
-                        // desperate try\r
-                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*/*");\r
-                    }\r
-                    i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\r
-                    startActivity(i);\r
-                    toastIt = false;\r
-                }\r
-                \r
-            } catch (IndexOutOfBoundsException e) {\r
-                Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);\r
-                \r
-            } catch (ActivityNotFoundException e) {\r
-                Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");\r
-                \r
-            } catch (Throwable th) {\r
-                Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);\r
-                \r
-            } finally {\r
-                if (toastIt) {\r
-                    Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();\r
-                }\r
-            }\r
-            \r
-        }\r
-    }\r
-\r
-\r
-    @Override\r
-    public void onConfirmation(String callerTag) {\r
-        if (callerTag.equals(FTAG_CONFIRMATION)) {\r
-            if (mStorageManager.getFileById(mFile.getFileId()) != null) {\r
-                mLastRemoteOperation = new RemoveFileOperation( mFile, \r
-                                                                true, \r
-                                                                mStorageManager);\r
-                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());\r
-                mLastRemoteOperation.execute(wc, this, mHandler);\r
-                \r
-                boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
-                getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
-            }\r
-        }\r
-    }\r
-    \r
-    @Override\r
-    public void onNeutral(String callerTag) {\r
-        File f = null;\r
-        if (mFile.isDown() && (f = new File(mFile.getStoragePath())).exists()) {\r
-            f.delete();\r
-            mFile.setStoragePath(null);\r
-            mStorageManager.saveFile(mFile);\r
-            updateFileDetails(mFile, mAccount);\r
-        }\r
-    }\r
-    \r
-    @Override\r
-    public void onCancel(String callerTag) {\r
-        Log.d(TAG, "REMOVAL CANCELED");\r
-    }\r
-    \r
-    \r
-    /**\r
-     * Check if the fragment was created with an empty layout. An empty fragment can't show file details, must be replaced.\r
-     * \r
-     * @return  True when the fragment was created with the empty layout.\r
-     */\r
-    public boolean isEmpty() {\r
-        return (mLayout == R.layout.file_details_empty || mFile == null || mAccount == null);\r
-    }\r
-\r
-    \r
-    /**\r
-     * {@inheritDoc}\r
-     */\r
-    public OCFile getFile(){\r
-        return mFile;\r
-    }\r
-    \r
-    /**\r
-     * Use this method to signal this Activity that it shall update its view.\r
-     * \r
-     * @param file : An {@link OCFile}\r
-     */\r
-    public void updateFileDetails(OCFile file, Account ocAccount) {\r
-        mFile = file;\r
-        if (ocAccount != null && ( \r
-                mStorageManager == null || \r
-                (mAccount != null && !mAccount.equals(ocAccount))\r
-           )) {\r
-            mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());\r
-        }\r
-        mAccount = ocAccount;\r
-        updateFileDetails(false, false);\r
-    }\r
-    \r
-\r
-    /**\r
-     * Updates the view with all relevant details about that file.\r
-     *\r
-     * TODO Remove parameter when the transferring state of files is kept in database. \r
-     * \r
-     * TODO REFACTORING! this method called 5 times before every time the fragment is shown! \r
-     * \r
-     * @param transferring      Flag signaling if the file should be considered as downloading or uploading, \r
-     *                          although {@link FileDownloaderBinder#isDownloading(Account, OCFile)}  and \r
-     *                          {@link FileUploaderBinder#isUploading(Account, OCFile)} return false.\r
-     *                          \r
-     * @param refresh           If 'true', try to refresh the hold file from the database\r
-     */\r
-    public void updateFileDetails(boolean transferring, boolean refresh) {\r
-\r
-        if (readyToShow()) {\r
-            \r
-            if (refresh && mStorageManager != null) {\r
-                mFile = mStorageManager.getFileByPath(mFile.getRemotePath());\r
-            }\r
-            \r
-            // set file details\r
-            setFilename(mFile.getFileName());\r
-            setFiletype(mFile.getMimetype());\r
-            setFilesize(mFile.getFileLength());\r
-            if(ocVersionSupportsTimeCreated()){\r
-                setTimeCreated(mFile.getCreationTimestamp());\r
-            }\r
-           \r
-            setTimeModified(mFile.getModificationTimestamp());\r
-            \r
-            CheckBox cb = (CheckBox)getView().findViewById(R.id.fdKeepInSync);\r
-            cb.setChecked(mFile.keepInSync());\r
-\r
-            // configure UI for depending upon local state of the file\r
-            //if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath()) || FileUploader.isUploading(mAccount, mFile.getRemotePath())) {\r
-            FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();\r
-            FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();\r
-            if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) || (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile))) {\r
-                setButtonsForTransferring();\r
-                \r
-            } else if (mFile.isDown()) {\r
-                \r
-                setButtonsForDown();\r
-                \r
-            } else {\r
-                // TODO load default preview image; when the local file is removed, the preview remains there\r
-                setButtonsForRemote();\r
-            }\r
-        }\r
-        getView().invalidate();\r
-    }\r
-    \r
-    \r
-    /**\r
-     * Checks if the fragment is ready to show details of a OCFile\r
-     *  \r
-     * @return  'True' when the fragment is ready to show details of a file\r
-     */\r
-    private boolean readyToShow() {\r
-        return (mFile != null && mAccount != null && mLayout == R.layout.file_details_fragment);        \r
-    }\r
-\r
-\r
-\r
-    /**\r
-     * Updates the filename in view\r
-     * @param filename to set\r
-     */\r
-    private void setFilename(String filename) {\r
-        TextView tv = (TextView) getView().findViewById(R.id.fdFilename);\r
-        if (tv != null)\r
-            tv.setText(filename);\r
-    }\r
-\r
-    /**\r
-     * Updates the MIME type in view\r
-     * @param mimetype to set\r
-     */\r
-    private void setFiletype(String mimetype) {\r
-        TextView tv = (TextView) getView().findViewById(R.id.fdType);\r
-        if (tv != null) {\r
-            String printableMimetype = DisplayUtils.convertMIMEtoPrettyPrint(mimetype);;        \r
-            tv.setText(printableMimetype);\r
-        }\r
-        ImageView iv = (ImageView) getView().findViewById(R.id.fdIcon);\r
-        if (iv != null) {\r
-            iv.setImageResource(DisplayUtils.getResourceId(mimetype));\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Updates the file size in view\r
-     * @param filesize in bytes to set\r
-     */\r
-    private void setFilesize(long filesize) {\r
-        TextView tv = (TextView) getView().findViewById(R.id.fdSize);\r
-        if (tv != null)\r
-            tv.setText(DisplayUtils.bytesToHumanReadable(filesize));\r
-    }\r
-    \r
-    /**\r
-     * Updates the time that the file was created in view\r
-     * @param milliseconds Unix time to set\r
-     */\r
-    private void setTimeCreated(long milliseconds){\r
-        TextView tv = (TextView) getView().findViewById(R.id.fdCreated);\r
-        TextView tvLabel = (TextView) getView().findViewById(R.id.fdCreatedLabel);\r
-        if(tv != null){\r
-            tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));\r
-            tv.setVisibility(View.VISIBLE);\r
-            tvLabel.setVisibility(View.VISIBLE);\r
-        }\r
-    }\r
-    \r
-    /**\r
-     * Updates the time that the file was last modified\r
-     * @param milliseconds Unix time to set\r
-     */\r
-    private void setTimeModified(long milliseconds){\r
-        TextView tv = (TextView) getView().findViewById(R.id.fdModified);\r
-        if(tv != null){\r
-            tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));\r
-        }\r
-    }\r
-    \r
-    /**\r
-     * Enables or disables buttons for a file being downloaded\r
-     */\r
-    private void setButtonsForTransferring() {\r
-        if (!isEmpty()) {\r
-            Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
-            downloadButton.setText(R.string.common_cancel);\r
-            //downloadButton.setEnabled(false);\r
-        \r
-            // let's protect the user from himself ;)\r
-            ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false);\r
-            ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(false);\r
-            ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(false);\r
-            getView().findViewById(R.id.fdKeepInSync).setEnabled(false);\r
-            \r
-            // show the progress bar for the transfer\r
-            ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.fdProgressBar);\r
-            progressBar.setVisibility(View.VISIBLE);\r
-            TextView progressText = (TextView)getView().findViewById(R.id.fdProgressText);\r
-            progressText.setVisibility(View.VISIBLE);\r
-            FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();\r
-            FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();\r
-            if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {\r
-                progressText.setText(R.string.downloader_download_in_progress_ticker);\r
-            } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile)) {\r
-                progressText.setText(R.string.uploader_upload_in_progress_ticker);\r
-            }\r
-        }\r
-    }\r
-    \r
-\r
-    /**\r
-     * Enables or disables buttons for a file locally available \r
-     */\r
-    private void setButtonsForDown() {\r
-        if (!isEmpty()) {\r
-            Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
-            downloadButton.setText(R.string.filedetails_sync_file);\r
-        \r
-            ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(true);\r
-            ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);\r
-            ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true);\r
-            getView().findViewById(R.id.fdKeepInSync).setEnabled(true);\r
-            \r
-            // hides the progress bar\r
-            ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.fdProgressBar);\r
-            progressBar.setVisibility(View.GONE);\r
-            TextView progressText = (TextView)getView().findViewById(R.id.fdProgressText);\r
-            progressText.setVisibility(View.GONE);\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Enables or disables buttons for a file not locally available \r
-     */\r
-    private void setButtonsForRemote() {\r
-        if (!isEmpty()) {\r
-            Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);\r
-            downloadButton.setText(R.string.filedetails_download);\r
-            \r
-            ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false);\r
-            ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);\r
-            ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true);\r
-            getView().findViewById(R.id.fdKeepInSync).setEnabled(true);\r
-            \r
-            // hides the progress bar\r
-            ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.fdProgressBar);\r
-            progressBar.setVisibility(View.GONE);\r
-            TextView progressText = (TextView)getView().findViewById(R.id.fdProgressText);\r
-            progressText.setVisibility(View.GONE);\r
-        }\r
-    }\r
-    \r
-\r
-    /**\r
-     * In ownCloud 3.X.X and 4.X.X there is a bug that SabreDAV does not return\r
-     * the time that the file was created. There is a chance that this will\r
-     * be fixed in future versions. Use this method to check if this version of\r
-     * ownCloud has this fix.\r
-     * @return True, if ownCloud the ownCloud version is supporting creation time\r
-     */\r
-    private boolean ocVersionSupportsTimeCreated(){\r
-        /*if(mAccount != null){\r
-            AccountManager accManager = (AccountManager) getActivity().getSystemService(Context.ACCOUNT_SERVICE);\r
-            OwnCloudVersion ocVersion = new OwnCloudVersion(accManager\r
-                    .getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION));\r
-            if(ocVersion.compareTo(new OwnCloudVersion(0x030000)) < 0) {\r
-                return true;\r
-            }\r
-        }*/\r
-        return false;\r
-    }\r
-    \r
-    \r
-    /**\r
-     * Once the file upload has finished -> update view\r
-     * \r
-     * Being notified about the finish of an upload is necessary for the next sequence:\r
-     *   1. Upload a big file.\r
-     *   2. Force a synchronization; if it finished before the upload, the file in transfer will be included in the local database and in the file list\r
-     *      of its containing folder; the the server includes it in the PROPFIND requests although it's not fully upload. \r
-     *   3. Click the file in the list to see its details.\r
-     *   4. Wait for the upload finishes; at this moment, the details view must be refreshed to enable the action buttons.\r
-     */\r
-    private class UploadFinishReceiver extends BroadcastReceiver {\r
-        @Override\r
-        public void onReceive(Context context, Intent intent) {\r
-            String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);\r
-\r
-            if (!isEmpty() && accountName.equals(mAccount.name)) {\r
-                boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false);\r
-                String uploadRemotePath = intent.getStringExtra(FileUploader.EXTRA_REMOTE_PATH);\r
-                boolean renamedInUpload = mFile.getRemotePath().equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH));\r
-                if (mFile.getRemotePath().equals(uploadRemotePath) ||\r
-                    renamedInUpload) {\r
-                    if (uploadWasFine) {\r
-                        mFile = mStorageManager.getFileByPath(uploadRemotePath);\r
-                    }\r
-                    if (renamedInUpload) {\r
-                        String newName = (new File(uploadRemotePath)).getName();\r
-                        Toast msg = Toast.makeText(getActivity().getApplicationContext(), String.format(getString(R.string.filedetails_renamed_in_upload_msg), newName), Toast.LENGTH_LONG);\r
-                        msg.show();\r
-                    }\r
-                    getSherlockActivity().removeStickyBroadcast(intent);    // not the best place to do this; a small refactorization of BroadcastReceivers should be done\r
-                    updateFileDetails(false, false);    // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server\r
-                }\r
-            }\r
-        }\r
-    }\r
-    \r
-\r
-    // this is a temporary class for sharing purposes, it need to be replaced in transfer service\r
-    @SuppressWarnings("unused")\r
-    private class ShareRunnable implements Runnable {\r
-        private String mPath;\r
-\r
-        public ShareRunnable(String path) {\r
-            mPath = path;\r
-        }\r
-        \r
-        public void run() {\r
-            AccountManager am = AccountManager.get(getActivity());\r
-            Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());\r
-            OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION));\r
-            String url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + AccountUtils.getWebdavPath(ocv);\r
-\r
-            Log.d("share", "sharing for version " + ocv.toString());\r
-\r
-            if (ocv.compareTo(new OwnCloudVersion(0x040000)) >= 0) {\r
-                String APPS_PATH = "/apps/files_sharing/";\r
-                String SHARE_PATH = "ajax/share.php";\r
-\r
-                String SHARED_PATH = "/apps/files_sharing/get.php?token=";\r
-                \r
-                final String WEBDAV_SCRIPT = "webdav.php";\r
-                final String WEBDAV_FILES_LOCATION = "/files/";\r
-                \r
-                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(account, getActivity().getApplicationContext());\r
-                HttpConnectionManagerParams params = new HttpConnectionManagerParams();\r
-                params.setMaxConnectionsPerHost(wc.getHostConfiguration(), 5);\r
-\r
-                //wc.getParams().setParameter("http.protocol.single-cookie-header", true);\r
-                //wc.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);\r
-\r
-                PostMethod post = new PostMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + APPS_PATH + SHARE_PATH);\r
-\r
-                post.addRequestHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8" );\r
-                post.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));\r
-                List<NameValuePair> formparams = new ArrayList<NameValuePair>();\r
-                Log.d("share", mPath+"");\r
-                formparams.add(new BasicNameValuePair("sources",mPath));\r
-                formparams.add(new BasicNameValuePair("uid_shared_with", "public"));\r
-                formparams.add(new BasicNameValuePair("permissions", "0"));\r
-                post.setRequestEntity(new StringRequestEntity(URLEncodedUtils.format(formparams, HTTP.UTF_8)));\r
-\r
-                int status;\r
-                try {\r
-                    PropFindMethod find = new PropFindMethod(url+"/");\r
-                    find.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));\r
-                    Log.d("sharer", ""+ url+"/");\r
-                    \r
-                    for (org.apache.commons.httpclient.Header a : find.getRequestHeaders()) {\r
-                        Log.d("sharer-h", a.getName() + ":"+a.getValue());\r
-                    }\r
-                    \r
-                    int status2 = wc.executeMethod(find);\r
-\r
-                    Log.d("sharer", "propstatus "+status2);\r
-                    \r
-                    GetMethod get = new GetMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + "/");\r
-                    get.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));\r
-                    \r
-                    status2 = wc.executeMethod(get);\r
-\r
-                    Log.d("sharer", "getstatus "+status2);\r
-                    Log.d("sharer", "" + get.getResponseBodyAsString());\r
-                    \r
-                    for (org.apache.commons.httpclient.Header a : get.getResponseHeaders()) {\r
-                        Log.d("sharer", a.getName() + ":"+a.getValue());\r
-                    }\r
-\r
-                    status = wc.executeMethod(post);\r
-                    for (org.apache.commons.httpclient.Header a : post.getRequestHeaders()) {\r
-                        Log.d("sharer-h", a.getName() + ":"+a.getValue());\r
-                    }\r
-                    for (org.apache.commons.httpclient.Header a : post.getResponseHeaders()) {\r
-                        Log.d("sharer", a.getName() + ":"+a.getValue());\r
-                    }\r
-                    String resp = post.getResponseBodyAsString();\r
-                    Log.d("share", ""+post.getURI().toString());\r
-                    Log.d("share", "returned status " + status);\r
-                    Log.d("share", " " +resp);\r
-                    \r
-                    if(status != HttpStatus.SC_OK ||resp == null || resp.equals("") || resp.startsWith("false")) {\r
-                        return;\r
-                     }\r
-\r
-                    JSONObject jsonObject = new JSONObject (resp);\r
-                    String jsonStatus = jsonObject.getString("status");\r
-                    if(!jsonStatus.equals("success")) throw new Exception("Error while sharing file status != success");\r
-                    \r
-                    String token = jsonObject.getString("data");\r
-                    String uri = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + SHARED_PATH + token; \r
-                    Log.d("Actions:shareFile ok", "url: " + uri);   \r
-                    \r
-                } catch (Exception e) {\r
-                    e.printStackTrace();\r
-                }\r
-                \r
-            } else if (ocv.compareTo(new OwnCloudVersion(0x030000)) >= 0) {\r
-                \r
-            }\r
-        }\r
-    }\r
-    \r
-    public void onDismiss(EditNameDialog dialog) {\r
-        if (dialog.getResult()) {\r
-            String newFilename = dialog.getNewFilename();\r
-            Log.d(TAG, "name edit dialog dismissed with new name " + newFilename);\r
-            mLastRemoteOperation = new RenameFileOperation( mFile, \r
-                                                            mAccount, \r
-                                                            newFilename, \r
-                                                            new FileDataStorageManager(mAccount, getActivity().getContentResolver()));\r
-            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());\r
-            mLastRemoteOperation.execute(wc, this, mHandler);\r
-            boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
-            getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
-        }\r
-    }\r
-    \r
-    \r
-    /**\r
-     * {@inheritDoc}\r
-     */\r
-    @Override\r
-    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {\r
-        if (operation.equals(mLastRemoteOperation)) {\r
-            if (operation instanceof RemoveFileOperation) {\r
-                onRemoveFileOperationFinish((RemoveFileOperation)operation, result);\r
-                \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
-    private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {\r
-        boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
-        getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
-        \r
-        if (result.isSuccess()) {\r
-            Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);\r
-            msg.show();\r
-            if (inDisplayActivity) {\r
-                // double pane\r
-                FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();\r
-                transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment\r
-                transaction.commit();\r
-                mContainerActivity.onFileStateChanged();\r
-            } else {\r
-                getActivity().finish();\r
-            }\r
-                \r
-        } else {\r
-            Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); \r
-            msg.show();\r
-            if (result.isSslRecoverableException()) {\r
-                // TODO show the SSL warning dialog\r
-            }\r
-        }\r
-    }\r
-    \r
-    private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) {\r
-        boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
-        getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
-        \r
-        if (result.isSuccess()) {\r
-            updateFileDetails(((RenameFileOperation)operation).getFile(), mAccount);\r
-            mContainerActivity.onFileStateChanged();\r
-            \r
-        } else {\r
-            if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {\r
-                Toast msg = Toast.makeText(getActivity(), R.string.rename_local_fail_msg, Toast.LENGTH_LONG); \r
-                msg.show();\r
-                // TODO throw again the new rename dialog\r
-            } else {\r
-                Toast msg = Toast.makeText(getActivity(), R.string.rename_server_fail_msg, Toast.LENGTH_LONG); \r
-                msg.show();\r
-                if (result.isSslRecoverableException()) {\r
-                    // TODO show the SSL warning dialog\r
-                }\r
-            }\r
-        }\r
-    }\r
-    \r
-    private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {\r
-        boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
-        getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
-\r
-        if (!result.isSuccess()) {\r
-            if (result.getCode() == ResultCode.SYNC_CONFLICT) {\r
-                Intent i = new Intent(getActivity(), ConflictsResolveActivity.class);\r
-                i.putExtra(ConflictsResolveActivity.EXTRA_FILE, mFile);\r
-                i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, mAccount);\r
-                startActivity(i);\r
-                \r
-            } else {\r
-                Toast msg = Toast.makeText(getActivity(), R.string.sync_file_fail_msg, Toast.LENGTH_LONG); \r
-                msg.show();\r
-            }\r
-            \r
-            if (mFile.isDown()) {\r
-                setButtonsForDown();\r
-                \r
-            } else {\r
-                setButtonsForRemote();\r
-            }\r
-            \r
-        } else {\r
-            if (operation.transferWasRequested()) {\r
-                setButtonsForTransferring();\r
-                mContainerActivity.onFileStateChanged();    // this is not working; FileDownloader won't do NOTHING at all until this method finishes, so \r
-                                                            // checking the service to see if the file is downloading results in FALSE\r
-            } else {\r
-                Toast msg = Toast.makeText(getActivity(), R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); \r
-                msg.show();\r
-                if (mFile.isDown()) {\r
-                    setButtonsForDown();\r
-                    \r
-                } else {\r
-                    setButtonsForRemote();\r
-                }\r
-            }\r
-        }\r
-    }\r
-    \r
-    \r
-    public void listenForTransferProgress() {\r
-        if (mProgressListener != null) {\r
-            if (mContainerActivity.getFileDownloaderBinder() != null) {\r
-                mContainerActivity.getFileDownloaderBinder().addDatatransferProgressListener(mProgressListener, mAccount, mFile);\r
-            }\r
-            if (mContainerActivity.getFileUploaderBinder() != null) {\r
-                mContainerActivity.getFileUploaderBinder().addDatatransferProgressListener(mProgressListener, mAccount, mFile);\r
-            }\r
-        }\r
-    }\r
-    \r
-    \r
-    public void leaveTransferProgress() {\r
-        if (mProgressListener != null) {\r
-            if (mContainerActivity.getFileDownloaderBinder() != null) {\r
-                mContainerActivity.getFileDownloaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, mFile);\r
-            }\r
-            if (mContainerActivity.getFileUploaderBinder() != null) {\r
-                mContainerActivity.getFileUploaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, mFile);\r
-            }\r
-        }\r
-    }\r
-\r
-\r
-    \r
-    /**\r
-     * Helper class responsible for updating the progress bar shown for file uploading or downloading  \r
-     * \r
-     * @author David A. Velasco\r
-     */\r
-    private class ProgressListener implements OnDatatransferProgressListener {\r
-        int mLastPercent = 0;\r
-        WeakReference<ProgressBar> mProgressBar = null;\r
-        \r
-        ProgressListener(ProgressBar progressBar) {\r
-            mProgressBar = new WeakReference<ProgressBar>(progressBar);\r
-        }\r
-        \r
-        @Override\r
-        public void onTransferProgress(long progressRate) {\r
-            // old method, nothing here\r
-        };\r
-\r
-        @Override\r
-        public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filename) {\r
-            int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));\r
-            if (percent != mLastPercent) {\r
-                ProgressBar pb = mProgressBar.get();\r
-                if (pb != null) {\r
-                    pb.setProgress(percent);\r
-                    pb.postInvalidate();\r
-                }\r
-            }\r
-            mLastPercent = percent;\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.fragment;
+
+import java.io.File;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.StringRequestEntity;
+import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
+import org.apache.http.HttpStatus;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.protocol.HTTP;
+import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
+import org.json.JSONObject;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+//import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v4.app.FragmentTransaction;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.webkit.MimeTypeMap;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapFactory.Options;
+import android.graphics.Point;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.FragmentTransaction;
+import android.util.Log;
+import android.view.Display;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.webkit.MimeTypeMap;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+
+import com.actionbarsherlock.app.SherlockFragment;
+import com.owncloud.android.AccountUtils;
+import com.owncloud.android.DisplayUtils;
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.authenticator.AccountAuthenticator;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.files.services.FileObserverService;
+import com.owncloud.android.files.services.FileUploader;
+import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
+import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
+import com.owncloud.android.network.OwnCloudClientUtils;
+import com.owncloud.android.operations.OnRemoteOperationListener;
+import com.owncloud.android.operations.RemoteOperation;
+import com.owncloud.android.operations.RemoteOperationResult;
+import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.operations.RemoveFileOperation;
+import com.owncloud.android.operations.RenameFileOperation;
+import com.owncloud.android.operations.SynchronizeFileOperation;
+import com.owncloud.android.ui.activity.ConflictsResolveActivity;
+import com.owncloud.android.ui.activity.FileDetailActivity;
+import com.owncloud.android.ui.activity.FileDisplayActivity;
+import com.owncloud.android.ui.dialog.EditNameDialog;
+import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
+import com.owncloud.android.utils.OwnCloudVersion;
+
+import com.owncloud.android.R;
+
+import eu.alefzero.webdav.OnDatatransferProgressListener;
+import eu.alefzero.webdav.WebdavClient;
+import eu.alefzero.webdav.WebdavUtils;
+
+
+/**
+ * This Fragment is used to display the details about a file.
+ * 
+ * @author Bartek Przybylski
+ * @author David A. Velasco
+ */
+public class FileDetailFragment extends SherlockFragment implements
+        OnClickListener, 
+        ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener, EditNameDialogListener,
+        FileFragment {
+
+    public static final String EXTRA_FILE = "FILE";
+    public static final String EXTRA_ACCOUNT = "ACCOUNT";
+
+    private FileFragment.ContainerActivity mContainerActivity;
+    
+    private int mLayout;
+    private View mView;
+    private OCFile mFile;
+    private Account mAccount;
+    private FileDataStorageManager mStorageManager;
+    
+    private UploadFinishReceiver mUploadFinishReceiver;
+    public ProgressListener mProgressListener;
+    
+    private Handler mHandler;
+    private RemoteOperation mLastRemoteOperation;
+    
+    private static final String TAG = FileDetailFragment.class.getSimpleName();
+    public static final String FTAG = "FileDetails"; 
+    public static final String FTAG_CONFIRMATION = "REMOVE_CONFIRMATION_FRAGMENT";
+    
+
+    /**
+     * Creates an empty details fragment.
+     * 
+     * It's necessary to keep a public constructor without parameters; the system uses it when tries to reinstantiate a fragment automatically. 
+     */
+    public FileDetailFragment() {
+        mFile = null;
+        mAccount = null;
+        mStorageManager = null;
+        mLayout = R.layout.file_details_empty;
+        mProgressListener = null;
+    }
+    
+    
+    /**
+     * Creates a details fragment.
+     * 
+     * When 'fileToDetail' or 'ocAccount' are null, creates a dummy layout (to use when a file wasn't tapped before).
+     * 
+     * @param fileToDetail      An {@link OCFile} to show in the fragment
+     * @param ocAccount         An ownCloud account; needed to start downloads
+     */
+    public FileDetailFragment(OCFile fileToDetail, Account ocAccount) {
+        mFile = fileToDetail;
+        mAccount = ocAccount;
+        mStorageManager = null; // we need a context to init this; the container activity is not available yet at this moment 
+        mLayout = R.layout.file_details_empty;
+        mProgressListener = null;
+    }
+    
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mHandler = new Handler();
+    }
+    
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        super.onCreateView(inflater, container, savedInstanceState);
+        
+        if (savedInstanceState != null) {
+            mFile = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE);
+            mAccount = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_ACCOUNT);
+        }
+        
+        if(mFile != null && mAccount != null) {
+            mLayout = R.layout.file_details_fragment;
+        }
+        
+        View view = null;
+        view = inflater.inflate(mLayout, container, false);
+        mView = view;
+        
+        if (mLayout == R.layout.file_details_fragment) {
+            mView.findViewById(R.id.fdKeepInSync).setOnClickListener(this);
+            mView.findViewById(R.id.fdRenameBtn).setOnClickListener(this);
+            mView.findViewById(R.id.fdDownloadBtn).setOnClickListener(this);
+            mView.findViewById(R.id.fdOpenBtn).setOnClickListener(this);
+            mView.findViewById(R.id.fdRemoveBtn).setOnClickListener(this);
+            //mView.findViewById(R.id.fdShareBtn).setOnClickListener(this);
+            ProgressBar progressBar = (ProgressBar)mView.findViewById(R.id.fdProgressBar);
+            mProgressListener = new ProgressListener(progressBar);
+        }
+        
+        updateFileDetails(false, false);
+        return view;
+    }
+    
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        try {
+            mContainerActivity = (ContainerActivity) activity;
+            
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString() + " must implement " + FileDetailFragment.ContainerActivity.class.getSimpleName());
+        }
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        if (mAccount != null) {
+            mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());
+        }
+    }
+        
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putParcelable(FileDetailFragment.EXTRA_FILE, mFile);
+        outState.putParcelable(FileDetailFragment.EXTRA_ACCOUNT, mAccount);
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        listenForTransferProgress();
+    }
+    
+    @Override
+    public void onResume() {
+        super.onResume();
+        mUploadFinishReceiver = new UploadFinishReceiver();
+        IntentFilter filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);
+        getActivity().registerReceiver(mUploadFinishReceiver, filter);
+
+    }
+
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        if (mUploadFinishReceiver != null) {
+            getActivity().unregisterReceiver(mUploadFinishReceiver);
+            mUploadFinishReceiver = null;
+        }
+    }
+
+    
+    @Override
+    public void onStop() {
+        super.onStop();
+        leaveTransferProgress();
+    }
+
+    
+    @Override
+    public View getView() {
+        return super.getView() == null ? mView : super.getView();
+    }
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.fdDownloadBtn: {
+                FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
+                FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
+                if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {
+                    downloaderBinder.cancel(mAccount, mFile);
+                    if (mFile.isDown()) {
+                        setButtonsForDown();
+                    } else {
+                        setButtonsForRemote();
+                    }
+
+                } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile)) {
+                    uploaderBinder.cancel(mAccount, mFile);
+                    if (!mFile.fileExists()) {
+                        // TODO make something better
+                        if (getActivity() instanceof FileDisplayActivity) {
+                            // double pane
+                            FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
+                            transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FTAG); // empty FileDetailFragment
+                            transaction.commit();
+                            mContainerActivity.onFileStateChanged();
+                        } else {
+                            getActivity().finish();
+                        }
+                        
+                    } else if (mFile.isDown()) {
+                        setButtonsForDown();
+                    } else {
+                        setButtonsForRemote();
+                    }
+                    
+                } else {
+                    mLastRemoteOperation = new SynchronizeFileOperation(mFile, null, mStorageManager, mAccount, true, false, getActivity());
+                    WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
+                    mLastRemoteOperation.execute(wc, this, mHandler);
+                
+                    // update ui 
+                    boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
+                    getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
+                    
+                }
+                break;
+            }
+            case R.id.fdKeepInSync: {
+                CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync);
+                mFile.setKeepInSync(cb.isChecked());
+                mStorageManager.saveFile(mFile);
+                
+                /// register the OCFile instance in the observer service to monitor local updates;
+                /// if necessary, the file is download 
+                Intent intent = new Intent(getActivity().getApplicationContext(),
+                                           FileObserverService.class);
+                intent.putExtra(FileObserverService.KEY_FILE_CMD,
+                           (cb.isChecked()?
+                                   FileObserverService.CMD_ADD_OBSERVED_FILE:
+                                   FileObserverService.CMD_DEL_OBSERVED_FILE));
+                intent.putExtra(FileObserverService.KEY_CMD_ARG_FILE, mFile);
+                intent.putExtra(FileObserverService.KEY_CMD_ARG_ACCOUNT, mAccount);
+                getActivity().startService(intent);
+                
+                if (mFile.keepInSync()) {
+                    onClick(getView().findViewById(R.id.fdDownloadBtn));    // force an immediate synchronization
+                }
+                break;
+            }
+            case R.id.fdRenameBtn: {
+                EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), mFile.getFileName(), this);
+                dialog.show(getFragmentManager(), "nameeditdialog");
+                break;
+            }   
+            case R.id.fdRemoveBtn: {
+                ConfirmationDialogFragment confDialog = ConfirmationDialogFragment.newInstance(
+                        R.string.confirmation_remove_alert,
+                        new String[]{mFile.getFileName()},
+                        mFile.isDown() ? R.string.confirmation_remove_remote_and_local : R.string.confirmation_remove_remote,
+                        mFile.isDown() ? R.string.confirmation_remove_local : -1,
+                        R.string.common_cancel);
+                confDialog.setOnConfirmationListener(this);
+                confDialog.show(getFragmentManager(), FTAG_CONFIRMATION);
+                break;
+            }
+            case R.id.fdOpenBtn: {
+                openFile();
+                break;
+            }
+            default:
+                Log_OC.e(TAG, "Incorrect view clicked!");
+        }
+        
+        /* else if (v.getId() == R.id.fdShareBtn) {
+            Thread t = new Thread(new ShareRunnable(mFile.getRemotePath()));
+            t.start();
+        }*/
+    }
+    
+    
+    /**
+     * Opens mFile.
+     */
+    private void openFile() {
+        
+        String storagePath = mFile.getStoragePath();
+        String encodedStoragePath = WebdavUtils.encodePath(storagePath);
+        try {
+            Intent i = new Intent(Intent.ACTION_VIEW);
+            i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mFile.getMimetype());
+            i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+            startActivity(i);
+            
+        } catch (Throwable t) {
+            Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
+            boolean toastIt = true; 
+            String mimeType = "";
+            try {
+                Intent i = new Intent(Intent.ACTION_VIEW);
+                mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
+                if (mimeType == null || !mimeType.equals(mFile.getMimetype())) {
+                    if (mimeType != null) {
+                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);
+                    } else {
+                        // desperate try
+                        i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*/*");
+                    }
+                    i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+                    startActivity(i);
+                    toastIt = false;
+                }
+                
+            } catch (IndexOutOfBoundsException e) {
+                Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
+                
+            } catch (ActivityNotFoundException e) {
+                Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
+                
+            } catch (Throwable th) {
+                Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);
+                
+            } finally {
+                if (toastIt) {
+                    Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();
+                }
+            }
+            
+        }
+    }
+
+
+    @Override
+    public void onConfirmation(String callerTag) {
+        if (callerTag.equals(FTAG_CONFIRMATION)) {
+            if (mStorageManager.getFileById(mFile.getFileId()) != null) {
+                mLastRemoteOperation = new RemoveFileOperation( mFile, 
+                                                                true, 
+                                                                mStorageManager);
+                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
+                mLastRemoteOperation.execute(wc, this, mHandler);
+                
+                boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
+                getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
+            }
+        }
+    }
+    
+    @Override
+    public void onNeutral(String callerTag) {
+        File f = null;
+        if (mFile.isDown() && (f = new File(mFile.getStoragePath())).exists()) {
+            f.delete();
+            mFile.setStoragePath(null);
+            mStorageManager.saveFile(mFile);
+            updateFileDetails(mFile, mAccount);
+        }
+    }
+    
+    @Override
+    public void onCancel(String callerTag) {
+        Log.d(TAG, "REMOVAL CANCELED");
+    }
+    
+    
+    /**
+     * Check if the fragment was created with an empty layout. An empty fragment can't show file details, must be replaced.
+     * 
+     * @return  True when the fragment was created with the empty layout.
+     */
+    public boolean isEmpty() {
+        return (mLayout == R.layout.file_details_empty || mFile == null || mAccount == null);
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public OCFile getFile(){
+        return mFile;
+    }
+    
+    /**
+     * Use this method to signal this Activity that it shall update its view.
+     * 
+     * @param file : An {@link OCFile}
+     */
+    public void updateFileDetails(OCFile file, Account ocAccount) {
+        mFile = file;
+        if (ocAccount != null && ( 
+                mStorageManager == null || 
+                (mAccount != null && !mAccount.equals(ocAccount))
+           )) {
+            mStorageManager = new FileDataStorageManager(ocAccount, getActivity().getApplicationContext().getContentResolver());
+        }
+        mAccount = ocAccount;
+        updateFileDetails(false, false);
+    }
+
+    /**
+     * Updates the view with all relevant details about that file.
+     *
+     * TODO Remove parameter when the transferring state of files is kept in database. 
+     * 
+     * TODO REFACTORING! this method called 5 times before every time the fragment is shown! 
+     * 
+     * @param transferring      Flag signaling if the file should be considered as downloading or uploading, 
+     *                          although {@link FileDownloaderBinder#isDownloading(Account, OCFile)}  and 
+     *                          {@link FileUploaderBinder#isUploading(Account, OCFile)} return false.
+     *                          
+     * @param refresh           If 'true', try to refresh the hold file from the database
+     */
+    public void updateFileDetails(boolean transferring, boolean refresh) {
+
+        if (readyToShow()) {
+            
+            if (refresh && mStorageManager != null) {
+                mFile = mStorageManager.getFileByPath(mFile.getRemotePath());
+            }
+            
+            // set file details
+            setFilename(mFile.getFileName());
+            setFiletype(mFile.getMimetype());
+            setFilesize(mFile.getFileLength());
+            if(ocVersionSupportsTimeCreated()){
+                setTimeCreated(mFile.getCreationTimestamp());
+            }
+           
+            setTimeModified(mFile.getModificationTimestamp());
+            
+            CheckBox cb = (CheckBox)getView().findViewById(R.id.fdKeepInSync);
+            cb.setChecked(mFile.keepInSync());
+
+            // configure UI for depending upon local state of the file
+            //if (FileDownloader.isDownloading(mAccount, mFile.getRemotePath()) || FileUploader.isUploading(mAccount, mFile.getRemotePath())) {
+            FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
+            FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
+            if (transferring || (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) || (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile))) {
+                setButtonsForTransferring();
+                
+            } else if (mFile.isDown()) {
+                
+                setButtonsForDown();
+                
+            } else {
+                // TODO load default preview image; when the local file is removed, the preview remains there
+                setButtonsForRemote();
+            }
+        }
+        getView().invalidate();
+    }
+    
+    
+    /**
+     * Checks if the fragment is ready to show details of a OCFile
+     *  
+     * @return  'True' when the fragment is ready to show details of a file
+     */
+    private boolean readyToShow() {
+        return (mFile != null && mAccount != null && mLayout == R.layout.file_details_fragment);        
+    }
+
+
+    /**
+     * Updates the filename in view
+     * @param filename to set
+     */
+    private void setFilename(String filename) {
+        TextView tv = (TextView) getView().findViewById(R.id.fdFilename);
+        if (tv != null)
+            tv.setText(filename);
+    }
+
+    /**
+     * Updates the MIME type in view
+     * @param mimetype to set
+     */
+    private void setFiletype(String mimetype) {
+        TextView tv = (TextView) getView().findViewById(R.id.fdType);
+        if (tv != null) {
+            String printableMimetype = DisplayUtils.convertMIMEtoPrettyPrint(mimetype);;        
+            tv.setText(printableMimetype);
+        }
+        ImageView iv = (ImageView) getView().findViewById(R.id.fdIcon);
+        if (iv != null) {
+            iv.setImageResource(DisplayUtils.getResourceId(mimetype));
+        }
+    }
+
+    /**
+     * Updates the file size in view
+     * @param filesize in bytes to set
+     */
+    private void setFilesize(long filesize) {
+        TextView tv = (TextView) getView().findViewById(R.id.fdSize);
+        if (tv != null)
+            tv.setText(DisplayUtils.bytesToHumanReadable(filesize));
+    }
+    
+    /**
+     * Updates the time that the file was created in view
+     * @param milliseconds Unix time to set
+     */
+    private void setTimeCreated(long milliseconds){
+        TextView tv = (TextView) getView().findViewById(R.id.fdCreated);
+        TextView tvLabel = (TextView) getView().findViewById(R.id.fdCreatedLabel);
+        if(tv != null){
+            tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));
+            tv.setVisibility(View.VISIBLE);
+            tvLabel.setVisibility(View.VISIBLE);
+        }
+    }
+    
+    /**
+     * Updates the time that the file was last modified
+     * @param milliseconds Unix time to set
+     */
+    private void setTimeModified(long milliseconds){
+        TextView tv = (TextView) getView().findViewById(R.id.fdModified);
+        if(tv != null){
+            tv.setText(DisplayUtils.unixTimeToHumanReadable(milliseconds));
+        }
+    }
+    
+    /**
+     * Enables or disables buttons for a file being downloaded
+     */
+    private void setButtonsForTransferring() {
+        if (!isEmpty()) {
+            Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);
+            downloadButton.setText(R.string.common_cancel);
+            //downloadButton.setEnabled(false);
+        
+            // let's protect the user from himself ;)
+            ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false);
+            ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(false);
+            ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(false);
+            getView().findViewById(R.id.fdKeepInSync).setEnabled(false);
+            
+            // show the progress bar for the transfer
+            ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.fdProgressBar);
+            progressBar.setVisibility(View.VISIBLE);
+            TextView progressText = (TextView)getView().findViewById(R.id.fdProgressText);
+            progressText.setVisibility(View.VISIBLE);
+            FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
+            FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
+            if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {
+                progressText.setText(R.string.downloader_download_in_progress_ticker);
+            } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile)) {
+                progressText.setText(R.string.uploader_upload_in_progress_ticker);
+            }
+        }
+    }
+
+    /**
+     * Enables or disables buttons for a file locally available 
+     */
+    private void setButtonsForDown() {
+        if (!isEmpty()) {
+            Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);
+            downloadButton.setText(R.string.filedetails_sync_file);
+        
+            ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(true);
+            ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);
+            ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true);
+            getView().findViewById(R.id.fdKeepInSync).setEnabled(true);
+            
+            // hides the progress bar
+            ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.fdProgressBar);
+            progressBar.setVisibility(View.GONE);
+            TextView progressText = (TextView)getView().findViewById(R.id.fdProgressText);
+            progressText.setVisibility(View.GONE);
+        }
+    }
+
+    /**
+     * Enables or disables buttons for a file not locally available 
+     */
+    private void setButtonsForRemote() {
+        if (!isEmpty()) {
+            Button downloadButton = (Button) getView().findViewById(R.id.fdDownloadBtn);
+            downloadButton.setText(R.string.filedetails_download);
+            
+            ((Button) getView().findViewById(R.id.fdOpenBtn)).setEnabled(false);
+            ((Button) getView().findViewById(R.id.fdRenameBtn)).setEnabled(true);
+            ((Button) getView().findViewById(R.id.fdRemoveBtn)).setEnabled(true);
+            getView().findViewById(R.id.fdKeepInSync).setEnabled(true);
+            
+            // hides the progress bar
+            ProgressBar progressBar = (ProgressBar)getView().findViewById(R.id.fdProgressBar);
+            progressBar.setVisibility(View.GONE);
+            TextView progressText = (TextView)getView().findViewById(R.id.fdProgressText);
+            progressText.setVisibility(View.GONE);
+        }
+    }
+    
+
+    /**
+     * In ownCloud 3.X.X and 4.X.X there is a bug that SabreDAV does not return
+     * the time that the file was created. There is a chance that this will
+     * be fixed in future versions. Use this method to check if this version of
+     * ownCloud has this fix.
+     * @return True, if ownCloud the ownCloud version is supporting creation time
+     */
+    private boolean ocVersionSupportsTimeCreated(){
+        /*if(mAccount != null){
+            AccountManager accManager = (AccountManager) getActivity().getSystemService(Context.ACCOUNT_SERVICE);
+            OwnCloudVersion ocVersion = new OwnCloudVersion(accManager
+                    .getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION));
+            if(ocVersion.compareTo(new OwnCloudVersion(0x030000)) < 0) {
+                return true;
+            }
+        }*/
+        return false;
+    }
+    
+
+    /**
+     * Once the file upload has finished -> update view
+     * 
+     * Being notified about the finish of an upload is necessary for the next sequence:
+     *   1. Upload a big file.
+     *   2. Force a synchronization; if it finished before the upload, the file in transfer will be included in the local database and in the file list
+     *      of its containing folder; the the server includes it in the PROPFIND requests although it's not fully upload. 
+     *   3. Click the file in the list to see its details.
+     *   4. Wait for the upload finishes; at this moment, the details view must be refreshed to enable the action buttons.
+     */
+    private class UploadFinishReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);
+
+            if (!isEmpty() && accountName.equals(mAccount.name)) {
+                boolean uploadWasFine = intent.getBooleanExtra(FileUploader.EXTRA_UPLOAD_RESULT, false);
+                String uploadRemotePath = intent.getStringExtra(FileUploader.EXTRA_REMOTE_PATH);
+                boolean renamedInUpload = mFile.getRemotePath().equals(intent.getStringExtra(FileUploader.EXTRA_OLD_REMOTE_PATH));
+                if (mFile.getRemotePath().equals(uploadRemotePath) ||
+                    renamedInUpload) {
+                    if (uploadWasFine) {
+                        mFile = mStorageManager.getFileByPath(uploadRemotePath);
+                    }
+                    if (renamedInUpload) {
+                        String newName = (new File(uploadRemotePath)).getName();
+                        Toast msg = Toast.makeText(getActivity().getApplicationContext(), String.format(getString(R.string.filedetails_renamed_in_upload_msg), newName), Toast.LENGTH_LONG);
+                        msg.show();
+                    }
+                    getSherlockActivity().removeStickyBroadcast(intent);    // not the best place to do this; a small refactorization of BroadcastReceivers should be done
+                    updateFileDetails(false, false);    // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server
+                }
+            }
+        }
+    }
+    
+
+    // this is a temporary class for sharing purposes, it need to be replaced in transfer service
+    @SuppressWarnings("unused")
+    private class ShareRunnable implements Runnable {
+        private String mPath;
+
+        public ShareRunnable(String path) {
+            mPath = path;
+        }
+        
+        public void run() {
+            AccountManager am = AccountManager.get(getActivity());
+            Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());
+            OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION));
+            String url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + AccountUtils.getWebdavPath(ocv);
+
+            Log.d("share", "sharing for version " + ocv.toString());
+
+            if (ocv.compareTo(new OwnCloudVersion(0x040000)) >= 0) {
+                String APPS_PATH = "/apps/files_sharing/";
+                String SHARE_PATH = "ajax/share.php";
+
+                String SHARED_PATH = "/apps/files_sharing/get.php?token=";
+                
+                final String WEBDAV_SCRIPT = "webdav.php";
+                final String WEBDAV_FILES_LOCATION = "/files/";
+                
+                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(account, getActivity().getApplicationContext());
+                HttpConnectionManagerParams params = new HttpConnectionManagerParams();
+                params.setMaxConnectionsPerHost(wc.getHostConfiguration(), 5);
+
+                //wc.getParams().setParameter("http.protocol.single-cookie-header", true);
+                //wc.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
+
+                PostMethod post = new PostMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + APPS_PATH + SHARE_PATH);
+
+                post.addRequestHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8" );
+                post.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));
+                List<NameValuePair> formparams = new ArrayList<NameValuePair>();
+                Log.d("share", mPath+"");
+                formparams.add(new BasicNameValuePair("sources",mPath));
+                formparams.add(new BasicNameValuePair("uid_shared_with", "public"));
+                formparams.add(new BasicNameValuePair("permissions", "0"));
+                post.setRequestEntity(new StringRequestEntity(URLEncodedUtils.format(formparams, HTTP.UTF_8)));
+
+                int status;
+                try {
+                    PropFindMethod find = new PropFindMethod(url+"/");
+                    find.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));
+                    Log.d("sharer", ""+ url+"/");
+                    
+                    for (org.apache.commons.httpclient.Header a : find.getRequestHeaders()) {
+                        Log.d("sharer-h", a.getName() + ":"+a.getValue());
+                    }
+                    
+                    int status2 = wc.executeMethod(find);
+
+                    Log.d("sharer", "propstatus "+status2);
+                    
+                    GetMethod get = new GetMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + "/");
+                    get.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));
+                    
+                    status2 = wc.executeMethod(get);
+
+                    Log.d("sharer", "getstatus "+status2);
+                    Log.d("sharer", "" + get.getResponseBodyAsString());
+                    
+                    for (org.apache.commons.httpclient.Header a : get.getResponseHeaders()) {
+                        Log.d("sharer", a.getName() + ":"+a.getValue());
+                    }
+
+                    status = wc.executeMethod(post);
+                    for (org.apache.commons.httpclient.Header a : post.getRequestHeaders()) {
+                        Log.d("sharer-h", a.getName() + ":"+a.getValue());
+                    }
+                    for (org.apache.commons.httpclient.Header a : post.getResponseHeaders()) {
+                        Log.d("sharer", a.getName() + ":"+a.getValue());
+                    }
+                    String resp = post.getResponseBodyAsString();
+                    Log.d("share", ""+post.getURI().toString());
+                    Log.d("share", "returned status " + status);
+                    Log.d("share", " " +resp);
+                    
+                    if(status != HttpStatus.SC_OK ||resp == null || resp.equals("") || resp.startsWith("false")) {
+                        return;
+                     }
+
+                    JSONObject jsonObject = new JSONObject (resp);
+                    String jsonStatus = jsonObject.getString("status");
+                    if(!jsonStatus.equals("success")) throw new Exception("Error while sharing file status != success");
+                    
+                    String token = jsonObject.getString("data");
+                    String uri = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + SHARED_PATH + token; 
+                    Log.d("Actions:shareFile ok", "url: " + uri);   
+                    
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+                
+            } else if (ocv.compareTo(new OwnCloudVersion(0x030000)) >= 0) {
+                
+            }
+        }
+    }
+    
+    public void onDismiss(EditNameDialog dialog) {
+        if (dialog.getResult()) {
+            String newFilename = dialog.getNewFilename();
+            Log.d(TAG, "name edit dialog dismissed with new name " + newFilename);
+            mLastRemoteOperation = new RenameFileOperation( mFile, 
+                                                            mAccount, 
+                                                            newFilename, 
+                                                            new FileDataStorageManager(mAccount, getActivity().getContentResolver()));
+            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
+            mLastRemoteOperation.execute(wc, this, mHandler);
+            boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
+            getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
+        }
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
+        if (operation.equals(mLastRemoteOperation)) {
+            if (operation instanceof RemoveFileOperation) {
+                onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
+                
+            } else if (operation instanceof RenameFileOperation) {
+                onRenameFileOperationFinish((RenameFileOperation)operation, result);
+                
+            } else if (operation instanceof SynchronizeFileOperation) {
+                onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);
+            }
+        }
+    }
+    
+    
+    private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) {
+        boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
+        getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
+        
+        if (result.isSuccess()) {
+            Toast msg = Toast.makeText(getActivity().getApplicationContext(), R.string.remove_success_msg, Toast.LENGTH_LONG);
+            msg.show();
+            if (inDisplayActivity) {
+                // double pane
+                FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
+                transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment
+                transaction.commit();
+                mContainerActivity.onFileStateChanged();
+            } else {
+                getActivity().finish();
+            }
+                
+        } else {
+            Toast msg = Toast.makeText(getActivity(), R.string.remove_fail_msg, Toast.LENGTH_LONG); 
+            msg.show();
+            if (result.isSslRecoverableException()) {
+                // TODO show the SSL warning dialog
+            }
+        }
+    }
+    
+    private void onRenameFileOperationFinish(RenameFileOperation operation, RemoteOperationResult result) {
+        boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
+        getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
+        
+        if (result.isSuccess()) {
+            updateFileDetails(((RenameFileOperation)operation).getFile(), mAccount);
+            mContainerActivity.onFileStateChanged();
+            
+        } else {
+            if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {
+                Toast msg = Toast.makeText(getActivity(), R.string.rename_local_fail_msg, Toast.LENGTH_LONG); 
+                msg.show();
+                // TODO throw again the new rename dialog
+            } else {
+                Toast msg = Toast.makeText(getActivity(), R.string.rename_server_fail_msg, Toast.LENGTH_LONG); 
+                msg.show();
+                if (result.isSslRecoverableException()) {
+                    // TODO show the SSL warning dialog
+                }
+            }
+        }
+    }
+    
+    private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {
+        boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
+        getActivity().dismissDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
+
+        if (!result.isSuccess()) {
+            if (result.getCode() == ResultCode.SYNC_CONFLICT) {
+                Intent i = new Intent(getActivity(), ConflictsResolveActivity.class);
+                i.putExtra(ConflictsResolveActivity.EXTRA_FILE, mFile);
+                i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, mAccount);
+                startActivity(i);
+                
+            } else {
+                Toast msg = Toast.makeText(getActivity(), R.string.sync_file_fail_msg, Toast.LENGTH_LONG); 
+                msg.show();
+            }
+            
+            if (mFile.isDown()) {
+                setButtonsForDown();
+                
+            } else {
+                setButtonsForRemote();
+            }
+            
+        } else {
+            if (operation.transferWasRequested()) {
+                setButtonsForTransferring();
+                mContainerActivity.onFileStateChanged();    // this is not working; FileDownloader won't do NOTHING at all until this method finishes, so 
+                                                            // checking the service to see if the file is downloading results in FALSE
+            } else {
+                Toast msg = Toast.makeText(getActivity(), R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG); 
+                msg.show();
+                if (mFile.isDown()) {
+                    setButtonsForDown();
+                    
+                } else {
+                    setButtonsForRemote();
+                }
+            }
+        }
+    }
+    
+    
+    public void listenForTransferProgress() {
+        if (mProgressListener != null) {
+            if (mContainerActivity.getFileDownloaderBinder() != null) {
+                mContainerActivity.getFileDownloaderBinder().addDatatransferProgressListener(mProgressListener, mAccount, mFile);
+            }
+            if (mContainerActivity.getFileUploaderBinder() != null) {
+                mContainerActivity.getFileUploaderBinder().addDatatransferProgressListener(mProgressListener, mAccount, mFile);
+            }
+        }
+    }
+    
+    
+    public void leaveTransferProgress() {
+        if (mProgressListener != null) {
+            if (mContainerActivity.getFileDownloaderBinder() != null) {
+                mContainerActivity.getFileDownloaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, mFile);
+            }
+            if (mContainerActivity.getFileUploaderBinder() != null) {
+                mContainerActivity.getFileUploaderBinder().removeDatatransferProgressListener(mProgressListener, mAccount, mFile);
+            }
+        }
+    }
+
+
+    
+    /**
+     * Helper class responsible for updating the progress bar shown for file uploading or downloading  
+     * 
+     * @author David A. Velasco
+     */
+    private class ProgressListener implements OnDatatransferProgressListener {
+        int mLastPercent = 0;
+        WeakReference<ProgressBar> mProgressBar = null;
+        
+        ProgressListener(ProgressBar progressBar) {
+            mProgressBar = new WeakReference<ProgressBar>(progressBar);
+        }
+        
+        @Override
+        public void onTransferProgress(long progressRate) {
+            // old method, nothing here
+        };
+
+        @Override
+        public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filename) {
+            int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));
+            if (percent != mLastPercent) {
+                ProgressBar pb = mProgressBar.get();
+                if (pb != null) {
+                    pb.setProgress(percent);
+                    pb.postInvalidate();
+                }
+            }
+            mLastPercent = percent;
+        }
+
+    };
+
+}
\ No newline at end of file
index 51f78b7..2b16bd7 100644 (file)
@@ -35,6 +35,7 @@ import android.widget.AdapterView;
 import android.widget.ImageView;
 import android.widget.ListView;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 
 /**
@@ -76,10 +77,10 @@ public class LocalFileListFragment extends FragmentListView {
      */
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-        Log.i(TAG, "onCreateView() start");
+        Log_OC.i(TAG, "onCreateView() start");
         View v = super.onCreateView(inflater, container, savedInstanceState);
         getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
-        Log.i(TAG, "onCreateView() end");
+        Log_OC.i(TAG, "onCreateView() end");
         return v;
     }    
 
@@ -89,30 +90,30 @@ public class LocalFileListFragment extends FragmentListView {
      */
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
-        Log.i(TAG, "onActivityCreated() start");
+        Log_OC.i(TAG, "onActivityCreated() start");
         
         super.onCreate(savedInstanceState);
         mAdapter = new LocalFileListAdapter(mContainerActivity.getInitialDirectory(), getActivity());
         setListAdapter(mAdapter);
         
         if (savedInstanceState != null) {
-            Log.i(TAG, "savedInstanceState is not null");
+            Log_OC.i(TAG, "savedInstanceState is not null");
             int position = savedInstanceState.getInt(SAVED_LIST_POSITION);
             setReferencePosition(position);
         }
         
-        Log.i(TAG, "onActivityCreated() stop");
+        Log_OC.i(TAG, "onActivityCreated() stop");
     }
     
     
     @Override
     public void onSaveInstanceState(Bundle savedInstanceState) {
-        Log.i(TAG, "onSaveInstanceState() start");
+        Log_OC.i(TAG, "onSaveInstanceState() start");
         
         savedInstanceState.putInt(SAVED_LIST_POSITION, getReferencePosition());
         
         
-        Log.i(TAG, "onSaveInstanceState() stop");
+        Log_OC.i(TAG, "onSaveInstanceState() stop");
     }
     
     
@@ -144,7 +145,7 @@ public class LocalFileListFragment extends FragmentListView {
             }
             
         } else {
-            Log.w(TAG, "Null object in ListAdapter!!");
+            Log_OC.w(TAG, "Null object in ListAdapter!!");
         }
     }
 
@@ -203,7 +204,7 @@ public class LocalFileListFragment extends FragmentListView {
         
         // if that's not a directory -> List its parent
         if(!directory.isDirectory()){
-            Log.w(TAG, "You see, that is not a directory -> " + directory.toString());
+            Log_OC.w(TAG, "You see, that is not a directory -> " + directory.toString());
             directory = directory.getParentFile();
         }
 
@@ -225,7 +226,7 @@ public class LocalFileListFragment extends FragmentListView {
         String [] result = null;
         SparseBooleanArray positions = mList.getCheckedItemPositions();
         if (positions.size() > 0) {
-            Log.d(TAG, "Returning " + positions.size() + " selected files");
+            Log_OC.d(TAG, "Returning " + positions.size() + " selected files");
             result = new String[positions.size()];
             for (int i=0; i<positions.size(); i++) {
                 result[i] = ((File) mList.getItemAtPosition(positions.keyAt(i))).getAbsolutePath();
index 90a06c0..fe25025 100644 (file)
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
@@ -100,14 +101,14 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
      */
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
-        Log.i(TAG, "onActivityCreated() start");
+        Log_OC.i(TAG, "onActivityCreated() start");
         
         super.onActivityCreated(savedInstanceState);
         mAdapter = new FileListListAdapter(mContainerActivity.getInitialDirectory(), mContainerActivity.getStorageManager(), getActivity(), mContainerActivity);
         setListAdapter(mAdapter);
         
         if (savedInstanceState != null) {
-            Log.i(TAG, "savedInstanceState is not null");
+            Log_OC.i(TAG, "savedInstanceState is not null");
             int position = savedInstanceState.getInt(SAVED_LIST_POSITION);
             setReferencePosition(position);
         }
@@ -117,18 +118,18 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
         
         mHandler = new Handler();
         
-        Log.i(TAG, "onActivityCreated() stop");
+        Log_OC.i(TAG, "onActivityCreated() stop");
     }
     
     
 
     @Override
     public void onSaveInstanceState(Bundle savedInstanceState) {
-        Log.i(TAG, "onSaveInstanceState() start");
+        Log_OC.i(TAG, "onSaveInstanceState() start");
         
         savedInstanceState.putInt(SAVED_LIST_POSITION, getReferencePosition());
         
-        Log.i(TAG, "onSaveInstanceState() stop");
+        Log_OC.i(TAG, "onSaveInstanceState() stop");
     }
     
     
@@ -149,7 +150,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
             }
             
         } else {
-            Log.d(TAG, "Null object in ListAdapter!!");
+            Log_OC.d(TAG, "Null object in ListAdapter!!");
         }
         
     }
@@ -276,7 +277,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
                     startActivity(i);
                     
                 } catch (Throwable t) {
-                    Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mTargetFile.getMimetype());
+                    Log_OC.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mTargetFile.getMimetype());
                     boolean toastIt = true; 
                     String mimeType = "";
                     try {
@@ -295,13 +296,13 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
                         }
                         
                     } catch (IndexOutOfBoundsException e) {
-                        Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
+                        Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
                         
                     } catch (ActivityNotFoundException e) {
-                        Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
+                        Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
                         
                     } catch (Throwable th) {
-                        Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);
+                        Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
                         
                     } finally {
                         if (toastIt) {
@@ -404,7 +405,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
         
             // If that's not a directory -> List its parent
             if(!directory.isDirectory()){
-                Log.w(TAG, "You see, that is not a directory -> " + directory.toString());
+                Log_OC.w(TAG, "You see, that is not a directory -> " + directory.toString());
                 directory = storageManager.getFileById(directory.getParentId());
             }
 
@@ -477,7 +478,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
     public void onDismiss(EditNameDialog dialog) {
         if (dialog.getResult()) {
             String newFilename = dialog.getNewFilename();
-            Log.d(TAG, "name edit dialog dismissed with new name " + newFilename);
+            Log_OC.d(TAG, "name edit dialog dismissed with new name " + newFilename);
             RemoteOperation operation = new RenameFileOperation(mTargetFile, 
                                                                 AccountUtils.getCurrentOwnCloudAccount(getActivity()), 
                                                                 newFilename, 
@@ -522,7 +523,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
     
     @Override
     public void onCancel(String callerTag) {
-        Log.d(TAG, "REMOVAL CANCELED");
+        Log_OC.d(TAG, "REMOVAL CANCELED");
     }
 
 
index 8d3912d..0255446 100644 (file)
@@ -30,12 +30,11 @@ import java.util.Set;
 
 import org.apache.commons.httpclient.methods.RequestEntity;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.network.ProgressiveDataTransferer;
 
 import eu.alefzero.webdav.OnDatatransferProgressListener;
 
-import android.util.Log;
-
 
 /**
  * A RequestEntity that represents a PIECE of a file.
@@ -136,7 +135,7 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres
             }
             
         } catch (IOException io) {
-            Log.e(TAG, io.getMessage());
+            Log_OC.e(TAG, io.getMessage());
             throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io);   
             
         }
index d60eabf..2f8073c 100644 (file)
@@ -32,12 +32,11 @@ import java.util.Set;
 
 import org.apache.commons.httpclient.methods.RequestEntity;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.network.ProgressiveDataTransferer;
 
 import eu.alefzero.webdav.OnDatatransferProgressListener;
 
-import android.util.Log;
-
 
 /**
  * A RequestEntity that represents a File.
@@ -123,7 +122,7 @@ public class FileRequestEntity implements RequestEntity, ProgressiveDataTransfer
             }
             
         } catch (IOException io) {
-            Log.e("FileRequestException", io.getMessage());
+            Log_OC.e("FileRequestException", io.getMessage());
             throw new RuntimeException("Ugly solution to workaround the default policy of retries when the server falls while uploading ; temporal fix; really", io);   
             
         } finally {
index df30dcb..c4df9d1 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
-package eu.alefzero.webdav;\r
-\r
-import java.io.BufferedInputStream;\r
-import java.io.File;\r
-import java.io.FileOutputStream;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-\r
-import org.apache.commons.httpclient.Credentials;\r
-import org.apache.commons.httpclient.HttpClient;\r
-import org.apache.commons.httpclient.HttpConnectionManager;\r
-import org.apache.commons.httpclient.HttpException;\r
-import org.apache.commons.httpclient.HttpMethodBase;\r
-import org.apache.commons.httpclient.HttpVersion;\r
-import org.apache.commons.httpclient.UsernamePasswordCredentials;\r
-import org.apache.commons.httpclient.auth.AuthScope;\r
-import org.apache.commons.httpclient.methods.GetMethod;\r
-import org.apache.commons.httpclient.methods.HeadMethod;\r
-import org.apache.commons.httpclient.methods.PutMethod;\r
-import org.apache.commons.httpclient.params.HttpMethodParams;\r
-import org.apache.http.HttpStatus;\r
-import org.apache.http.params.CoreProtocolPNames;\r
-import org.apache.jackrabbit.webdav.client.methods.DavMethod;\r
-import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;\r
-import org.apache.jackrabbit.webdav.client.methods.MkColMethod;\r
-\r
-import android.net.Uri;\r
-import android.util.Log;\r
-\r
-public class WebdavClient extends HttpClient {\r
-    private Uri mUri;\r
-    private Credentials mCredentials;\r
-    final private static String TAG = "WebdavClient";\r
-    private static final String USER_AGENT = "Android-ownCloud";\r
-    \r
-    private OnDatatransferProgressListener mDataTransferListener;\r
-    static private byte[] sExhaustBuffer = new byte[1024];\r
-    \r
-    /**\r
-     * Constructor\r
-     */\r
-    public WebdavClient(HttpConnectionManager connectionMgr) {\r
-        super(connectionMgr);\r
-        Log.d(TAG, "Creating WebdavClient");\r
-        getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT);\r
-        getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);\r
-    }\r
-\r
-    public void setCredentials(String username, String password) {\r
-        getParams().setAuthenticationPreemptive(true);\r
-        getState().setCredentials(AuthScope.ANY,\r
-                getCredentials(username, password));\r
-    }\r
-\r
-    private Credentials getCredentials(String username, String password) {\r
-        if (mCredentials == null)\r
-            mCredentials = new UsernamePasswordCredentials(username, password);\r
-        return mCredentials;\r
-    }\r
-    \r
-    /**\r
-     * Downloads a file in remoteFilepath to the local targetPath.\r
-     * \r
-     * @param remoteFilepath    Path to the file in the remote server, URL DECODED. \r
-     * @param targetFile        Local path to save the downloaded file.\r
-     * @return                  'True' when the file is successfully downloaded.\r
-     */\r
-    public boolean downloadFile(String remoteFilePath, File targetFile) {\r
-        boolean ret = false;\r
-        GetMethod get = new GetMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath));\r
-\r
-        try {\r
-            int status = executeMethod(get);\r
-            if (status == HttpStatus.SC_OK) {\r
-                targetFile.createNewFile();\r
-                BufferedInputStream bis = new BufferedInputStream(\r
-                        get.getResponseBodyAsStream());\r
-                FileOutputStream fos = new FileOutputStream(targetFile);\r
-\r
-                byte[] bytes = new byte[4096];\r
-                int readResult;\r
-                while ((readResult = bis.read(bytes)) != -1) {\r
-                    if (mDataTransferListener != null)\r
-                        mDataTransferListener.onTransferProgress(readResult);\r
-                    fos.write(bytes, 0, readResult);\r
-                }\r
-                fos.close();\r
-                ret = true;\r
-            } else {\r
-                exhaustResponse(get.getResponseBodyAsStream());\r
-            }\r
-            Log.e(TAG, "Download of " + remoteFilePath + " to " + targetFile + " finished with HTTP status " + status + (!ret?"(FAIL)":""));\r
-        } catch (Exception e) {\r
-            logException(e, "dowloading " + remoteFilePath);\r
-            \r
-        } finally {\r
-            if (!ret && targetFile.exists()) {\r
-                targetFile.delete();\r
-            }\r
-            get.releaseConnection();    // let the connection available for other methods\r
-        }\r
-        return ret;\r
-    }\r
-    \r
-    /**\r
-     * Deletes a remote file via webdav\r
-     * @param remoteFilePath       Remote file path of the file to delete, in URL DECODED format.\r
-     * @return\r
-     */\r
-    public boolean deleteFile(String remoteFilePath) {\r
-        boolean ret = false;\r
-        DavMethod delete = new DeleteMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath));\r
-        try {\r
-            int status = executeMethod(delete);\r
-            ret = (status == HttpStatus.SC_OK || status == HttpStatus.SC_ACCEPTED || status == HttpStatus.SC_NO_CONTENT);\r
-            exhaustResponse(delete.getResponseBodyAsStream());\r
-            \r
-            Log.e(TAG, "DELETE of " + remoteFilePath + " finished with HTTP status " + status +  (!ret?"(FAIL)":""));\r
-            \r
-        } catch (Exception e) {\r
-            logException(e, "deleting " + remoteFilePath);\r
-            \r
-        } finally {\r
-            delete.releaseConnection();    // let the connection available for other methods\r
-        }\r
-        return ret;\r
-    }\r
-\r
-    \r
-    public void setDataTransferProgressListener(OnDatatransferProgressListener listener) {\r
-        mDataTransferListener = listener;\r
-    }\r
-    \r
-    /**\r
-     * Creates or update a file in the remote server with the contents of a local file.\r
-     * \r
-     * @param localFile         Path to the local file to upload.\r
-     * @param remoteTarget      Remote path to the file to create or update, URL DECODED\r
-     * @param contentType       MIME type of the file.\r
-     * @return                  Status HTTP code returned by the server.\r
-     * @throws IOException      When a transport error that could not be recovered occurred while uploading the file to the server.\r
-     * @throws HttpException    When a violation of the HTTP protocol occurred. \r
-     */\r
-    public int putFile(String localFile, String remoteTarget, String contentType) throws HttpException, IOException {\r
-        int status = -1;\r
-        PutMethod put = new PutMethod(mUri.toString() + WebdavUtils.encodePath(remoteTarget));\r
-        \r
-        try {\r
-            File f = new File(localFile);\r
-            FileRequestEntity entity = new FileRequestEntity(f, contentType);\r
-            entity.addDatatransferProgressListener(mDataTransferListener);\r
-            put.setRequestEntity(entity);\r
-            status = executeMethod(put);\r
-            \r
-            exhaustResponse(put.getResponseBodyAsStream());\r
-            \r
-        } finally {\r
-            put.releaseConnection();    // let the connection available for other methods\r
-        }\r
-        return status;\r
-    }\r
-    \r
-    /**\r
-     * Tries to log in to the current URI, with the current credentials\r
-     * \r
-     * @return A {@link HttpStatus}-Code of the result. SC_OK is good.\r
-     */\r
-    public int tryToLogin() {\r
-        int status = 0;\r
-        HeadMethod head = new HeadMethod(mUri.toString());\r
-        try {\r
-            status = executeMethod(head);\r
-            boolean result = status == HttpStatus.SC_OK;\r
-            Log.d(TAG, "HEAD for " + mUri + " finished with HTTP status " + status + (!result?"(FAIL)":""));\r
-            exhaustResponse(head.getResponseBodyAsStream());\r
-            \r
-        } catch (Exception e) {\r
-            logException(e, "trying to login at " + mUri.toString());\r
-            \r
-        } finally {\r
-            head.releaseConnection();\r
-        }\r
-        return status;\r
-    }\r
-\r
-    /**\r
-     * Creates a remote directory with the received path.\r
-     * \r
-     * @param path      Path of the directory to create, URL DECODED\r
-     * @return          'True' when the directory is successfully created\r
-     */\r
-    public boolean createDirectory(String path) {\r
-        boolean result = false;\r
-        int status = -1;\r
-        MkColMethod mkcol = new MkColMethod(mUri.toString() + WebdavUtils.encodePath(path));\r
-        try {\r
-            Log.d(TAG, "Creating directory " + path);\r
-            status = executeMethod(mkcol);\r
-            Log.d(TAG, "Status returned: " + status);\r
-            result = mkcol.succeeded();\r
-            \r
-            Log.d(TAG, "MKCOL to " + path + " finished with HTTP status " + status + (!result?"(FAIL)":""));\r
-            exhaustResponse(mkcol.getResponseBodyAsStream());\r
-            \r
-        } catch (Exception e) {\r
-            logException(e, "creating directory " + path);\r
-            \r
-        } finally {\r
-            mkcol.releaseConnection();    // let the connection available for other methods\r
-        }\r
-        return result;\r
-    }\r
-    \r
-    \r
-    /**\r
-     * Check if a file exists in the OC server\r
-     * \r
-     * @return              'true' if the file exists; 'false' it doesn't exist\r
-     * @throws  Exception   When the existence could not be determined\r
-     */\r
-    public boolean existsFile(String path) throws IOException, HttpException {\r
-        HeadMethod head = new HeadMethod(mUri.toString() + WebdavUtils.encodePath(path));\r
-        try {\r
-            int status = executeMethod(head);\r
-            Log.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + ((status != HttpStatus.SC_OK)?"(FAIL)":""));\r
-            exhaustResponse(head.getResponseBodyAsStream());\r
-            return (status == HttpStatus.SC_OK);\r
-            \r
-        } finally {\r
-            head.releaseConnection();    // let the connection available for other methods\r
-        }\r
-    }\r
-\r
-\r
-    /**\r
-     * Requests the received method with the received timeout (milliseconds).\r
-     * \r
-     * Executes the method through the inherited HttpClient.executedMethod(method).\r
-     * \r
-     * Sets the socket and connection timeouts only for the method received.\r
-     * \r
-     * The timeouts are both in milliseconds; 0 means 'infinite'; < 0 means 'do not change the default'\r
-     * \r
-     * @param method            HTTP method request.\r
-     * @param readTimeout       Timeout to set for data reception\r
-     * @param conntionTimout    Timeout to set for connection establishment\r
-     */\r
-    public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws HttpException, IOException {\r
-        int oldSoTimeout = getParams().getSoTimeout();\r
-        int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout();\r
-        try {\r
-            if (readTimeout >= 0) { \r
-                method.getParams().setSoTimeout(readTimeout);   // this should be enough...\r
-                getParams().setSoTimeout(readTimeout);          // ... but this looks like necessary for HTTPS\r
-            }\r
-            if (connectionTimeout >= 0) {\r
-                getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);\r
-            }\r
-            return executeMethod(method);\r
-        } finally {\r
-            getParams().setSoTimeout(oldSoTimeout);\r
-            getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout);\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation.\r
-     * \r
-     * @param responseBodyAsStream      InputStream with the HTTP response to exhaust.\r
-     */\r
-    public void exhaustResponse(InputStream responseBodyAsStream) {\r
-        if (responseBodyAsStream != null) {\r
-            try {\r
-                while (responseBodyAsStream.read(sExhaustBuffer) >= 0);\r
-                responseBodyAsStream.close();\r
-            \r
-            } catch (IOException io) {\r
-                Log.e(TAG, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED", io);\r
-            }\r
-        }\r
-    }\r
-\r
-\r
-    /**\r
-     * Logs an exception triggered in a HTTP request. \r
-     * \r
-     * @param e         Caught exception.\r
-     * @param doing     Suffix to add at the end of the logged message.\r
-     */\r
-    private void logException(Exception e, String doing) {\r
-        if (e instanceof HttpException) {\r
-            Log.e(TAG, "HTTP violation while " + doing, e);\r
-\r
-        } else if (e instanceof IOException) {\r
-            Log.e(TAG, "Unrecovered transport exception while " + doing, e);\r
-\r
-        } else {\r
-            Log.e(TAG, "Unexpected exception while " + doing, e);\r
-        }\r
-    }\r
-\r
-    \r
-    /**\r
-     * Sets the connection and wait-for-data timeouts to be applied by default to the methods performed by this client.\r
-     */\r
-    public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) {\r
-            getParams().setSoTimeout(defaultDataTimeout);\r
-            getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout);\r
-    }\r
-\r
-    /**\r
-     * Sets the base URI for the helper methods that receive paths as parameters, instead of full URLs\r
-     * @param uri\r
-     */\r
-    public void setBaseUri(Uri uri) {\r
-        mUri = uri;\r
-    }\r
-\r
-    public Uri getBaseUri() {\r
-        return mUri;\r
-    }\r
-\r
-}\r
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License 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 eu.alefzero.webdav;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpConnectionManager;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.HttpMethodBase;
+import org.apache.commons.httpclient.HttpVersion;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.auth.AuthScope;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.HeadMethod;
+import org.apache.commons.httpclient.methods.PutMethod;
+import org.apache.commons.httpclient.params.HttpMethodParams;
+import org.apache.http.HttpStatus;
+import org.apache.http.params.CoreProtocolPNames;
+import org.apache.jackrabbit.webdav.client.methods.DavMethod;
+import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
+import org.apache.jackrabbit.webdav.client.methods.MkColMethod;
+
+import com.owncloud.android.Log_OC;
+
+import android.net.Uri;
+import android.util.Log;
+
+public class WebdavClient extends HttpClient {
+    private Uri mUri;
+    private Credentials mCredentials;
+    final private static String TAG = "WebdavClient";
+    private static final String USER_AGENT = "Android-ownCloud";
+    
+    private OnDatatransferProgressListener mDataTransferListener;
+    static private byte[] sExhaustBuffer = new byte[1024];
+    
+    /**
+     * Constructor
+     */
+    public WebdavClient(HttpConnectionManager connectionMgr) {
+        super(connectionMgr);
+        Log_OC.d(TAG, "Creating WebdavClient");
+        getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT);
+        getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
+    }
+
+    public void setCredentials(String username, String password) {
+        getParams().setAuthenticationPreemptive(true);
+        getState().setCredentials(AuthScope.ANY,
+                getCredentials(username, password));
+    }
+
+    private Credentials getCredentials(String username, String password) {
+        if (mCredentials == null)
+            mCredentials = new UsernamePasswordCredentials(username, password);
+        return mCredentials;
+    }
+    
+    /**
+     * Downloads a file in remoteFilepath to the local targetPath.
+     * 
+     * @param remoteFilepath    Path to the file in the remote server, URL DECODED. 
+     * @param targetFile        Local path to save the downloaded file.
+     * @return                  'True' when the file is successfully downloaded.
+     */
+    public boolean downloadFile(String remoteFilePath, File targetFile) {
+        boolean ret = false;
+        GetMethod get = new GetMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath));
+
+        try {
+            int status = executeMethod(get);
+            if (status == HttpStatus.SC_OK) {
+                targetFile.createNewFile();
+                BufferedInputStream bis = new BufferedInputStream(
+                        get.getResponseBodyAsStream());
+                FileOutputStream fos = new FileOutputStream(targetFile);
+
+                byte[] bytes = new byte[4096];
+                int readResult;
+                while ((readResult = bis.read(bytes)) != -1) {
+                    if (mDataTransferListener != null)
+                        mDataTransferListener.onTransferProgress(readResult);
+                    fos.write(bytes, 0, readResult);
+                }
+                fos.close();
+                ret = true;
+            } else {
+                exhaustResponse(get.getResponseBodyAsStream());
+            }
+            Log_OC.e(TAG, "Download of " + remoteFilePath + " to " + targetFile + " finished with HTTP status " + status + (!ret?"(FAIL)":""));
+            
+        } catch (Exception e) {
+            logException(e, "dowloading " + remoteFilePath);
+            
+        } finally {
+            if (!ret && targetFile.exists()) {
+                targetFile.delete();
+            }
+            get.releaseConnection();    // let the connection available for other methods
+        }
+        return ret;
+    }
+    
+    /**
+     * Deletes a remote file via webdav
+     * @param remoteFilePath       Remote file path of the file to delete, in URL DECODED format.
+     * @return
+     */
+    public boolean deleteFile(String remoteFilePath) {
+        boolean ret = false;
+        DavMethod delete = new DeleteMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath));
+        try {
+            int status = executeMethod(delete);
+            ret = (status == HttpStatus.SC_OK || status == HttpStatus.SC_ACCEPTED || status == HttpStatus.SC_NO_CONTENT);
+            exhaustResponse(delete.getResponseBodyAsStream());
+            
+            Log_OC.e(TAG, "DELETE of " + remoteFilePath + " finished with HTTP status " + status +  (!ret?"(FAIL)":""));
+            
+        } catch (Exception e) {
+            logException(e, "deleting " + remoteFilePath);
+            
+        } finally {
+            delete.releaseConnection();    // let the connection available for other methods
+        }
+        return ret;
+    }
+
+    
+    public void setDataTransferProgressListener(OnDatatransferProgressListener listener) {
+        mDataTransferListener = listener;
+    }
+    
+    /**
+     * Creates or update a file in the remote server with the contents of a local file.
+     * 
+     * @param localFile         Path to the local file to upload.
+     * @param remoteTarget      Remote path to the file to create or update, URL DECODED
+     * @param contentType       MIME type of the file.
+     * @return                  Status HTTP code returned by the server.
+     * @throws IOException      When a transport error that could not be recovered occurred while uploading the file to the server.
+     * @throws HttpException    When a violation of the HTTP protocol occurred. 
+     */
+    public int putFile(String localFile, String remoteTarget, String contentType) throws HttpException, IOException {
+        int status = -1;
+        PutMethod put = new PutMethod(mUri.toString() + WebdavUtils.encodePath(remoteTarget));
+        
+        try {
+            File f = new File(localFile);
+            FileRequestEntity entity = new FileRequestEntity(f, contentType);
+            entity.addDatatransferProgressListener(mDataTransferListener);
+            put.setRequestEntity(entity);
+            status = executeMethod(put);
+            
+            exhaustResponse(put.getResponseBodyAsStream());
+            
+        } finally {
+            put.releaseConnection();    // let the connection available for other methods
+        }
+        return status;
+    }
+    
+    /**
+     * Tries to log in to the current URI, with the current credentials
+     * 
+     * @return A {@link HttpStatus}-Code of the result. SC_OK is good.
+     */
+    public int tryToLogin() {
+        int status = 0;
+        HeadMethod head = new HeadMethod(mUri.toString());
+        try {
+            status = executeMethod(head);
+            boolean result = status == HttpStatus.SC_OK;
+            Log_OC.d(TAG, "HEAD for " + mUri + " finished with HTTP status " + status + (!result?"(FAIL)":""));
+            exhaustResponse(head.getResponseBodyAsStream());
+            
+        } catch (Exception e) {
+            logException(e, "trying to login at " + mUri.toString());
+            
+        } finally {
+            head.releaseConnection();
+        }
+        return status;
+    }
+
+    /**
+     * Creates a remote directory with the received path.
+     * 
+     * @param path      Path of the directory to create, URL DECODED
+     * @return          'True' when the directory is successfully created
+     */
+    public boolean createDirectory(String path) {
+        boolean result = false;
+        int status = -1;
+        MkColMethod mkcol = new MkColMethod(mUri.toString() + WebdavUtils.encodePath(path));
+        try {
+            Log_OC.d(TAG, "Creating directory " + path);
+            status = executeMethod(mkcol);
+            Log_OC.d(TAG, "Status returned: " + status);
+            result = mkcol.succeeded();
+            
+            Log_OC.d(TAG, "MKCOL to " + path + " finished with HTTP status " + status + (!result?"(FAIL)":""));
+            exhaustResponse(mkcol.getResponseBodyAsStream());
+            
+        } catch (Exception e) {
+            logException(e, "creating directory " + path);
+            
+        } finally {
+            mkcol.releaseConnection();    // let the connection available for other methods
+        }
+        return result;
+    }
+    
+    
+    /**
+     * Check if a file exists in the OC server
+     * 
+     * @return              'true' if the file exists; 'false' it doesn't exist
+     * @throws  Exception   When the existence could not be determined
+     */
+    public boolean existsFile(String path) throws IOException, HttpException {
+        HeadMethod head = new HeadMethod(mUri.toString() + WebdavUtils.encodePath(path));
+        try {
+            int status = executeMethod(head);
+            Log_OC.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + ((status != HttpStatus.SC_OK)?"(FAIL)":""));
+            exhaustResponse(head.getResponseBodyAsStream());
+            return (status == HttpStatus.SC_OK);
+            
+        } finally {
+            head.releaseConnection();    // let the connection available for other methods
+        }
+    }
+
+    /**
+     * Requests the received method with the received timeout (milliseconds).
+     * 
+     * Executes the method through the inherited HttpClient.executedMethod(method).
+     * 
+     * Sets the socket and connection timeouts only for the method received.
+     * 
+     * The timeouts are both in milliseconds; 0 means 'infinite'; < 0 means 'do not change the default'
+     * 
+     * @param method            HTTP method request.
+     * @param readTimeout       Timeout to set for data reception
+     * @param conntionTimout    Timeout to set for connection establishment
+     */
+    public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws HttpException, IOException {
+        int oldSoTimeout = getParams().getSoTimeout();
+        int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout();
+        try {
+            if (readTimeout >= 0) { 
+                method.getParams().setSoTimeout(readTimeout);   // this should be enough...
+                getParams().setSoTimeout(readTimeout);          // ... but this looks like necessary for HTTPS
+            }
+            if (connectionTimeout >= 0) {
+                getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);
+            }
+            return executeMethod(method);
+        } finally {
+            getParams().setSoTimeout(oldSoTimeout);
+            getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout);
+        }
+    }
+
+    /**
+     * Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation.
+     * 
+     * @param responseBodyAsStream      InputStream with the HTTP response to exhaust.
+     */
+    public void exhaustResponse(InputStream responseBodyAsStream) {
+        if (responseBodyAsStream != null) {
+            try {
+                while (responseBodyAsStream.read(sExhaustBuffer) >= 0);
+                responseBodyAsStream.close();
+            
+            } catch (IOException io) {
+                Log_OC.e(TAG, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED", io);
+            }
+        }
+    }
+
+    /**
+     * Logs an exception triggered in a HTTP request. 
+     * 
+     * @param e         Caught exception.
+     * @param doing     Suffix to add at the end of the logged message.
+     */
+    private void logException(Exception e, String doing) {
+        if (e instanceof HttpException) {
+            Log_OC.e(TAG, "HTTP violation while " + doing, e);
+
+        } else if (e instanceof IOException) {
+            Log_OC.e(TAG, "Unrecovered transport exception while " + doing, e);
+
+        } else {
+            Log_OC.e(TAG, "Unexpected exception while " + doing, e);
+        }
+    }
+
+    
+    /**
+     * Sets the connection and wait-for-data timeouts to be applied by default to the methods performed by this client.
+     */
+    public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) {
+            getParams().setSoTimeout(defaultDataTimeout);
+            getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout);
+    }
+
+    /**
+     * Sets the base URI for the helper methods that receive paths as parameters, instead of full URLs
+     * @param uri
+     */
+    public void setBaseUri(Uri uri) {
+        mUri = uri;
+    }
+
+    public Uri getBaseUri() {
+        return mUri;
+    }
+
+}
index f76ee69..b474e20 100644 (file)
@@ -24,6 +24,8 @@ import org.apache.jackrabbit.webdav.property.DavProperty;
 import org.apache.jackrabbit.webdav.property.DavPropertyName;
 import org.apache.jackrabbit.webdav.property.DavPropertySet;
 
+import com.owncloud.android.Log_OC;
+
 import android.net.Uri;
 import android.util.Log;
 
@@ -89,7 +91,7 @@ public class WebdavEntry {
             }
 
         } else {
-            Log.e("WebdavEntry",
+            Log_OC.e("WebdavEntry",
                     "General fuckup, no status for webdav response");
         }
     }