-<?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="103020"
- android:versionName="1.3.20" xmlns:android="http://schemas.android.com/apk/res/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>
-
++ <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.FileUploader" >
- </service>
<service android:name=".files.services.InstantUploadService" />
- <receiver android:name=".files.InstantUploadBroadcastReceiver">\r
- <intent-filter>\r
- <action android:name="com.android.camera.NEW_PICTURE" />\r
- <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>
<resources>
<string name="app_name">ownCloud</string>
- <string name="whats_new">What\'s new</string>
<string name="main_password">Password:</string>
<string name="main_login">Username:</string>
<string name="main_button_login">Login</string>
<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="actionbar_mkdir">Create directory</string>
<string name="actionbar_search">Search</string>
<string name="actionbar_settings">Settings</string>
+ <string name="actionbar_see_details">Details</string>
+
<string name="prefs_category_general">General</string>
- <string name="prefs_category_trackmydevice">Device tracking</string>
<string name="prefs_add_session">Add new session</string>
<string name="prefs_create_img_thumbnails">Create image thumbnails</string>
<string name="prefs_select_oc_account">Select an account</string>
<string name="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>
<string name="setup_title">Connect to your %1$s</string>
<string name="setup_btn_connect">Connect</string>
<string name="uploader_btn_upload_text">Upload</string>
+ <string name="uploader_top_message">Choose upload directory:</string>
<string name="uploader_wrn_no_account_title">No account found</string>
<string name="uploader_wrn_no_account_text">There are no %1$s accounts on your device. Please setup an account first.</string>
<string name="uploader_wrn_no_account_setup_btn_text">Setup</string>
<string name="common_save_exit">Save & Exit</string>
<string name="common_exit">Leave %1$s</string>
<string name="common_error">Error</string>
+ <string name="common_loading">Loading …</string>
+ <string name="common_error_unknown">Unknown error</string>
<string name="about_title">About</string>
<string name="delete_account">Delete account</string>
<string name="create_account">Create account</string>
<string name="downloader_download_succeeded_content">%1$s was successfully downloaded</string>
<string name="downloader_download_failed_ticker">Download failed</string>
<string name="downloader_download_failed_content">Download of %1$s could not be completed</string>
+ <string name="downloader_not_downloaded_yet">Not downloaded yet</string>
<string name="common_choose_account">Choose account</string>
<string name="sync_string_contacts">Contacts</string>
<string name="sync_fail_ticker">Synchronization failed</string>
<string name="pincode_wrong">Incorrect App PIN</string>
<string name="pincode_removed">App PIN removed</string>
<string name="pincode_stored">App PIN stored</string>
-
+
+ <string name="media_notif_ticker">"%1$s music player"</string>
+ <string name="media_state_playing">"%1$s (playing)"</string>
+ <string name="media_state_loading">"%1$s (loading)"</string>
+ <string name="media_event_done">"%1$s playback finished"</string>
+ <string name="media_err_nothing_to_play">No media file found</string>
+ <string name="media_err_no_account">No account provided</string>
+ <string name="media_err_not_in_owncloud">File not in a valid account</string>
+ <string name="media_err_unsupported">Unsupported media codec</string>
+ <string name="media_err_io">Media file could not be read</string>
+ <string name="media_err_malformed">Media file not correctly encoded</string>
+ <string name="media_err_timeout">Too much time trying to play</string>
+ <string name="media_err_invalid_progressive_playback">Media file cannot be streamed</string>
+ <string name="media_err_unknown">Media file cannot be played with the stock media player</string>
+ <string name="media_err_security_ex">Security error trying to play %1$s</string>
+ <string name="media_err_io_ex">Input error trying to play %1$s</string>
+ <string name="media_err_unexpected">Unexpected error trying to play %1$s</string>
+ <string name="media_previous_description">Previous track button</string>
+ <string name="media_rewind_description">Rewind button</string>
+ <string name="media_play_pause_description">Play or pause button</string>
+ <string name="media_forward_description">Fast forward button</string>
+ <string name="media_next_description">Next track button</string>
<string-array name="prefs_trackmydevice_intervall_keys">
<item>15 Minutes</item>
<item>30 Minutes</item>
<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>
<string name="ssl_validator_label_L">Location:</string>
<string name="ssl_validator_label_validity">Validity:</string>
<string name="ssl_validator_label_validity_from">From:</string>
- <string name="ssl_validator_label_validity_to">To:</string>
- <string name="ssl_validator_label_signature">Signature:</string>
- <string name="ssl_validator_label_signature_algorithm">Algorithm:</string>
- <string name="text_placeholder">This is a placeholder</string>
+ <string name="ssl_validator_label_validity_to">To:</string>
+ <string name="ssl_validator_label_signature">Signature:</string>
+ <string name="ssl_validator_label_signature_algorithm">Algorithm:</string>
+
+ <string name="placeholder_sentence">This is a placeholder</string>
+ <string name="placeholder_filename">placeholder.txt</string>
+ <string name="placeholder_filetype">PNG Image</string>
+ <string name="placeholder_filesize">389 KB</string>
+ <string name="placeholder_timestamp">2012/05/18 12:23 PM</string>
+ <string name="placeholder_media_time">12:23:45</string>
+
<string name="instant_upload_on_wifi">Upload pictures via WiFi only</string>
<string name="instant_upload_path">/InstantUpload</string>
<string name="conflict_title">Update conflict</string>
<string name="conflict_keep_both">Keep both</string>
<string name="conflict_overwrite">Overwrite</string>
<string name="conflict_dont_upload">Don\'t upload</string>
-
+
+ <string name="preview_image_description">Image preview</string>
+ <string name="preview_image_error_unknown_format">This image can not be shown</string>
+ <string name="preview_image_error_out_of_memory">"Not enough memory to show this image</string>
+
<!-- we need to improve the communication of errors to the user -->
<string name="error__upload__local_file_not_copied">%1$s could not be copied to %2$s local directory</string>
<string name="actionbar_failed_instant_upload">Failed InstantUpload"</string>
<string name="failed_upload_retry_text">retry to upload the image: </string>
<string name="failed_upload_load_more_images">Load more Picrures</string>
<string name="failed_upload_retry_do_nothing_text">do nothing you are not online for instant upload</string>
-
- </resources>
+ <string name="failed_upload_failure_text">Failure Message: </string>
+ <string name="failed_upload_quota_exceeded_text">Please check your server configuration,maybe your quota is exceeded.</string>
+ </resources>
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;
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());
}
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());
}
}
} 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
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());
}
}
}
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 {
+ 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;
+ "=?", 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;
}
}
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,
}
} 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);
}
}
}
+ @Override
+ public Vector<OCFile> getDirectoryImages(OCFile directory) {
+ Vector<OCFile> ret = new Vector<OCFile>();
+ if (directory != null) {
+ // TODO better implementation, filtering in the access to database (if possible) instead of here
+ Vector<OCFile> tmp = getDirectoryContent(directory);
+ OCFile current = null;
+ for (int i=0; i<tmp.size(); i++) {
+ current = tmp.get(i);
+ if (current.isImage()) {
+ ret.add(current);
+ }
+ }
+ }
+ return ret;
+ }
+
}
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> {
* 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;
if (isDirectory()) {
mRemotePath += PATH_SEPARATOR;
}
- Log.d(TAG, "OCFile name changed to " + mRemotePath);
+ Log_OC.d(TAG, "OCFile name changed to " + mRemotePath);
}
}
return 0;
}
+ /** @return 'True' if the file contains audio */
+ public boolean isAudio() {
+ return (mMimeType != null && mMimeType.startsWith("audio/"));
+ }
+
+ /** @return 'True' if the file contains video */
+ public boolean isVideo() {
+ return (mMimeType != null && mMimeType.startsWith("video/"));
+ }
+
+ /** @return 'True' if the file contains an image */
+ public boolean isImage() {
+ return ((mMimeType != null && mMimeType.startsWith("image/")) ||
+ getMimeTypeFromName().startsWith("image/"));
+ }
+
+ public String getMimeTypeFromName() {
+ String extension = "";
+ int pos = mRemotePath.lastIndexOf('.');
+ if (pos >= 0) {
+ extension = mRemotePath.substring(pos + 1);
+ }
+ String result = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
+ return (result != null) ? result : "";
+ }
+
}
*/
package com.owncloud.android.db;
+import com.owncloud.android.Log_OC;
+
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
mDB.close();
}
- public boolean putFileForLater(String filepath, String account) {
+ public boolean putFileForLater(String filepath, String account, String message) {
ContentValues cv = new ContentValues();
cv.put("path", filepath);
cv.put("account", account);
cv.put("attempt", UPLOAD_STATUS_UPLOAD_LATER);
+ cv.put("message", message);
long result = mDB.insert(TABLE_INSTANT_UPLOAD, null, cv);
- Log.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;
}
- public int updateFileState(String filepath, Integer status) {
+ public int updateFileState(String filepath, Integer status, String message) {
ContentValues cv = new ContentValues();
cv.put("attempt", status);
+ cv.put("message", message);
int result = mDB.update(TABLE_INSTANT_UPLOAD, cv, "path=?", new String[] { filepath });
- Log.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;
}
*/
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;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_INSTANT_UPLOAD + " (" + " _id INTEGER PRIMARY KEY, " + " path TEXT,"
- + " account TEXT,attempt INTEGER);");
+ + " account TEXT,attempt INTEGER,message TEXT);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- db.execSQL("ALTER TABLE " + TABLE_INSTANT_UPLOAD + " ADD COLUMN attempt;");
+ if (oldVersion < 2) {
+ db.execSQL("ALTER TABLE " + TABLE_INSTANT_UPLOAD + " ADD COLUMN attempt INTEGER;");
+ }
+ db.execSQL("ALTER TABLE " + TABLE_INSTANT_UPLOAD + " ADD COLUMN message TEXT;");
}
}
import android.webkit.MimeTypeMap;
import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
import com.owncloud.android.authenticator.AccountAuthenticator;
import com.owncloud.android.db.DbHandler;
import com.owncloud.android.files.services.FileUploader;
+ import com.owncloud.android.utils.FileStorageUtils;
public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
- public static String INSTANT_UPLOAD_DIR = "/InstantUpload/";
private static String TAG = "PhotoTakenBroadcastReceiver";
private static final String[] CONTENT_PROJECTION = { Media.DATA, Media.DISPLAY_NAME, Media.MIME_TYPE, Media.SIZE };
private static String NEW_PHOTO_ACTION = "com.android.camera.NEW_PICTURE";
@Override
public void onReceive(Context context, Intent intent) {
- Log.d(TAG, "Received: " + intent.getAction());
+ Log_OC.d(TAG, "Received: " + intent.getAction());
if (intent.getAction().equals(android.net.ConnectivityManager.CONNECTIVITY_ACTION)) {
handleConnectivityAction(context, intent);
} else if (intent.getAction().equals(NEW_PHOTO_ACTION)) {
} 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());
}
}
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();
}
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;
}
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);
- db.putFileForLater(file_path, account.name);
+ db.putFileForLater(file_path, account.name, null);
db.close();
if (!isOnline(context) || (instantUploadViaWiFiOnly(context) && !isConnectedViaWiFi(context))) {
Intent i = new Intent(context, FileUploader.class);
i.putExtra(FileUploader.KEY_ACCOUNT, account);
i.putExtra(FileUploader.KEY_LOCAL_FILE, file_path);
- i.putExtra(FileUploader.KEY_REMOTE_FILE, INSTANT_UPLOAD_DIR + file_name);
+ i.putExtra(FileUploader.KEY_REMOTE_FILE, FileStorageUtils.getInstantUploadFilePath(file_name));
i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
i.putExtra(FileUploader.KEY_MIME_TYPE, mime_type);
i.putExtra(FileUploader.KEY_INSTANT_UPLOAD, true);
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;
}
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";
Intent i = new Intent(context, FileUploader.class);
i.putExtra(FileUploader.KEY_ACCOUNT, account);
i.putExtra(FileUploader.KEY_LOCAL_FILE, file_path);
- i.putExtra(FileUploader.KEY_REMOTE_FILE, INSTANT_UPLOAD_DIR + f.getName());
+ i.putExtra(FileUploader.KEY_REMOTE_FILE, FileStorageUtils.getInstantUploadFilePath(f.getName()));
i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
i.putExtra(FileUploader.KEY_INSTANT_UPLOAD, true);
context.startService(i);
} else {
- Log.w(TAG, "Instant upload file " + f.getAbsolutePath() + " dont exist anymore");
+ Log_OC.w(TAG, "Instant upload file " + f.getAbsolutePath() + " dont exist anymore");
}
} while (c.moveToNext());
}
-/* 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.util.Log;
+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 {
++ 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 = new Intent(this, FileDetailActivity.class);
++ 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;
- // TODO put something smart in the contentIntent below
- finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);
++ 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(ACCOUNT_NAME, download.getAccount().name);
++ added.putExtra(EXTRA_REMOTE_PATH, download.getRemotePath());
+ added.putExtra(EXTRA_FILE_PATH, download.getSavePath());
+ sendStickyBroadcast(added);
+ }
+
+}
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 android.widget.RemoteViews;
import android.widget.Toast;
+import com.owncloud.android.Log_OC;
import com.owncloud.android.R;
import com.owncloud.android.authenticator.AccountAuthenticator;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.db.DbHandler;
- import com.owncloud.android.files.InstantUploadBroadcastReceiver;
import com.owncloud.android.network.OwnCloudClientUtils;
import com.owncloud.android.operations.ChunkedUploadFileOperation;
import com.owncloud.android.operations.RemoteOperationResult;
import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.operations.UploadFileOperation;
+ import com.owncloud.android.ui.activity.FailedUploadActivity;
import com.owncloud.android.ui.activity.FileDetailActivity;
import com.owncloud.android.ui.activity.InstantUploadActivity;
import com.owncloud.android.ui.fragment.FileDetailFragment;
+ import com.owncloud.android.ui.preview.PreviewImageActivity;
+ import com.owncloud.android.ui.preview.PreviewImageFragment;
import com.owncloud.android.utils.OwnCloudVersion;
import eu.alefzero.webdav.OnDatatransferProgressListener;
/**
* Builds a key for mPendingUploads from the account and file to upload
*
- * @param account Account where the file to download is stored
- * @param file File to download
+ * @param account Account where the file to upload is stored
+ * @param file File to upload
*/
private String buildRemoteName(Account account, OCFile file) {
return account.name + file.getRemotePath();
@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();
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);
}
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;
}
}
mPendingUploads.putIfAbsent(uploadKey, newUpload);
newUpload.addDatatransferProgressListener(this);
+ newUpload.addDatatransferProgressListener((FileUploaderBinder)mBinder);
requestedUploads.add(uploadKey);
}
} 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;
}
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;
}
public IBinder onBind(Intent arg0) {
return mBinder;
}
+
+ /**
+ * Called when ALL the bound clients were onbound.
+ */
+ @Override
+ public boolean onUnbind(Intent intent) {
+ ((FileUploaderBinder)mBinder).clearListeners();
+ return false; // not accepting rebinding (default behaviour)
+ }
+
/**
* Binder to let client components to perform operations on the queue of
*
* It provides by itself the available operations.
*/
- public class FileUploaderBinder extends Binder {
-
+ public class FileUploaderBinder extends Binder implements OnDatatransferProgressListener {
+
+ /**
+ * Map of listeners that will be reported about progress of uploads from a {@link FileUploaderBinder} instance
+ */
+ private Map<String, OnDatatransferProgressListener> mBoundListeners = new HashMap<String, OnDatatransferProgressListener>();
+
/**
* Cancels a pending or current upload of a remote file.
*
upload.cancel();
}
}
+
+
+
+ public void clearListeners() {
+ mBoundListeners.clear();
+ }
+
+
+
/**
* Returns True when the file described by 'file' is being uploaded to
* the ownCloud account 'account' or waiting for it
*
- * If 'file' is a directory, returns 'true' if some of its descendant
- * files is downloading or waiting to download.
+ * If 'file' is a directory, returns 'true' if some of its descendant files is uploading or waiting to upload.
*
* @param account Owncloud account where the remote file will be stored.
* @param file A file that could be in the queue of pending uploads
String targetKey = buildRemoteName(account, file);
synchronized (mPendingUploads) {
if (file.isDirectory()) {
- // this can be slow if there are many downloads :(
+ // this can be slow if there are many uploads :(
Iterator<String> it = mPendingUploads.keySet().iterator();
boolean found = false;
while (it.hasNext() && !found) {
}
}
}
+
+
+ /**
+ * Adds a listener interested in the progress of the upload 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 upload 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(mCurrentUpload.getAccount(), mCurrentUpload.getFile());
+ OnDatatransferProgressListener boundListener = mBoundListeners.get(key);
+ if (boundListener != null) {
+ boundListener.onTransferProgress(progressRate, totalTransferredSoFar, totalToTransfer, fileName);
+ }
+ }
+
}
/**
// / create remote folder for instant uploads
if (mCurrentUpload.isRemoteFolderToBeCreated()) {
- mUploadClient.createDirectory(InstantUploadBroadcastReceiver.INSTANT_UPLOAD_DIR); // ignoring
- // result;
- // fail
- // could
- // just
- // mean
- // that
- // it
- // already
- // exists,
- // but
- // local
- // database
- // is
- // not
- // synchronized;
- // the
- // upload
- // will
- // be
- // tried
- // anyway
+ mUploadClient.createDirectory(InstantUploadService.INSTANT_UPLOAD_DIR);
+ // ignoring result fail could just mean that it already exists,
+ // but local database is not synchronized the upload will be
+ // tried anyway
}
// / perform the upload
} 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.");
}
}
}
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 {
file.setMimetype(we.contentType());
file.setModificationTimestamp(we.modifiedTimestamp());
file.setModificationTimestampAtLastSyncForData(we.modifiedTimestamp());
- // file.setEtag(mCurrentDownload.getEtag()); // TODO Etag, where
- // available
+ // file.setEtag(mCurrentUpload.getEtag()); // TODO Etag, where available
}
private boolean checkAndFixInstantUploadDirectory(FileDataStorageManager storageManager) {
- OCFile instantUploadDir = storageManager.getFileByPath(InstantUploadBroadcastReceiver.INSTANT_UPLOAD_DIR);
+ OCFile instantUploadDir = storageManager.getFileByPath(InstantUploadService.INSTANT_UPLOAD_DIR);
if (instantUploadDir == null) {
// first instant upload in the account, or never account not
// synchronized after the remote InstantUpload folder was created
- OCFile newDir = new OCFile(InstantUploadBroadcastReceiver.INSTANT_UPLOAD_DIR);
+ OCFile newDir = new OCFile(InstantUploadService.INSTANT_UPLOAD_DIR);
newDir.setMimetype("DIR");
OCFile path = storageManager.getFileByPath(OCFile.PATH_SEPARATOR);
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) {
*
* @param upload Upload operation starting.
*/
+ @SuppressWarnings("deprecation")
private void notifyUploadStart(UploadFileOperation upload) {
// / create status notification with a progress bar
mLastPercent = 0;
mNotification.contentView.setTextViewText(R.id.status_text,
String.format(getString(R.string.uploader_upload_in_progress_content), 0, upload.getFileName()));
mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon);
-
- // / includes a pending intent in the notification showing the details
- // view of the file
- Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+
+ /// includes a pending intent in the notification showing the details view of the file
+ Intent showDetailsIntent = null;
+ if (PreviewImageFragment.canBePreviewed(upload.getFile())) {
+ showDetailsIntent = new Intent(this, PreviewImageActivity.class);
+ } else {
+ showDetailsIntent = new Intent(this, FileDetailActivity.class);
+ showDetailsIntent.putExtra(FileDetailActivity.EXTRA_MODE, FileDetailActivity.MODE_DETAILS);
+ }
showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, upload.getFile());
showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, upload.getAccount());
showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
* @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);
// flag
mNotification.flags |= Notification.FLAG_AUTO_CANCEL;
mNotification.contentView = mDefaultNotificationContentView;
-
- // / includes a pending intent in the notification showing the
- // details view of the file
- Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+
+ /// includes a pending intent in the notification showing the details view of the file
+ Intent showDetailsIntent = null;
+ if (PreviewImageFragment.canBePreviewed(upload.getFile())) {
+ showDetailsIntent = new Intent(this, PreviewImageActivity.class);
+ } else {
+ showDetailsIntent = new Intent(this, FileDetailActivity.class);
+ showDetailsIntent.putExtra(FileDetailActivity.EXTRA_MODE, FileDetailActivity.MODE_DETAILS);
+ }
showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, upload.getFile());
showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, upload.getAccount());
showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
getString(R.string.uploader_upload_failed_ticker), System.currentTimeMillis());
finalNotification.flags |= Notification.FLAG_AUTO_CANCEL;
- Intent detailUploudIntent = new Intent(this, InstantUploadActivity.class);
- detailUploudIntent.putExtra(FileUploader.KEY_ACCOUNT, upload.getAccount());
- finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(),
- (int) System.currentTimeMillis(), detailUploudIntent, PendingIntent.FLAG_UPDATE_CURRENT
- | PendingIntent.FLAG_ONE_SHOT);
-
String content = null;
if (uploadResult.getCode() == ResultCode.LOCAL_STORAGE_FULL
|| uploadResult.getCode() == ResultCode.LOCAL_STORAGE_NOT_COPIED) {
// from a RemoteOperationResult and a RemoteOperation
content = String.format(getString(R.string.error__upload__local_file_not_copied), upload.getFileName(),
getString(R.string.app_name));
+ } else if (uploadResult.getCode() == ResultCode.QUOTA_EXCEEDED) {
+ content = getString(R.string.failed_upload_quota_exceeded_text);
} else {
content = String
.format(getString(R.string.uploader_upload_failed_content_single), upload.getFileName());
}
- finalNotification.setLatestEventInfo(getApplicationContext(),
- getString(R.string.uploader_upload_failed_ticker), content, finalNotification.contentIntent);
- mNotificationManager.notify(R.string.uploader_upload_failed_ticker, finalNotification);
+ // we add only for instant-uploads the InstantUploadActivity and the
+ // db entry
+ Intent detailUploadIntent = null;
+ if (upload.isInstant() && InstantUploadActivity.IS_ENABLED) {
+ detailUploadIntent = new Intent(this, InstantUploadActivity.class);
+ detailUploadIntent.putExtra(FileUploader.KEY_ACCOUNT, upload.getAccount());
+ } else {
+ detailUploadIntent = new Intent(this, FailedUploadActivity.class);
+ detailUploadIntent.putExtra(FailedUploadActivity.MESSAGE, content);
+ }
+ finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(),
+ (int) System.currentTimeMillis(), detailUploadIntent, PendingIntent.FLAG_UPDATE_CURRENT
+ | PendingIntent.FLAG_ONE_SHOT);
- DbHandler db = new DbHandler(this.getBaseContext());
- if (db.updateFileState(upload.getOriginalStoragePath(), DbHandler.UPLOAD_STATUS_UPLOAD_FAILED) == 0) {
- db.putFileForLater(upload.getOriginalStoragePath(), upload.getAccount().name);
+ if (upload.isInstant()) {
+ DbHandler db = null;
+ try {
+ db = new DbHandler(this.getBaseContext());
+ String message = uploadResult.getLogMessage() + " errorCode: " + uploadResult.getCode();
+ Log.e(TAG, message + " Http-Code: " + uploadResult.getHttpCode());
+ if (uploadResult.getCode() == ResultCode.QUOTA_EXCEEDED) {
+ message = getString(R.string.failed_upload_quota_exceeded_text);
+ }
+ if (db.updateFileState(upload.getOriginalStoragePath(), DbHandler.UPLOAD_STATUS_UPLOAD_FAILED,
+ message) == 0) {
+ db.putFileForLater(upload.getOriginalStoragePath(), upload.getAccount().name, message);
+ }
+ } finally {
+ if (db != null) {
+ db.close();
+ }
+ }
}
- db.close();
+ finalNotification.setLatestEventInfo(getApplicationContext(),
+ getString(R.string.uploader_upload_failed_ticker), content, finalNotification.contentIntent);
+ mNotificationManager.notify(R.string.uploader_upload_failed_ticker, finalNotification);
}
}
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 {
private static String TAG = "InstantUploadService";
// TODO make it configurable over the settings dialog
- public static String INSTANT_UPLOAD_DIR = "/InstantUpload";
+ public static final String INSTANT_UPLOAD_DIR = "/InstantUpload";
private UploaderRunnable mUploaderRunnable;
@Override
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;
}
-
+
if (mUploaderRunnable == null) {
mUploaderRunnable = new UploaderRunnable();
}
-
+
String filename = intent.getStringExtra(KEY_DISPLAY_NAME);
String filepath = intent.getStringExtra(KEY_FILE_PATH);
String mimetype = intent.getStringExtra(KEY_MIME_TYPE);
Account account = intent.getParcelableExtra(KEY_ACCOUNT);
long filesize = intent.getLongExtra(KEY_FILE_SIZE, -1);
-
+
mUploaderRunnable.addElementToQueue(filename, filepath, mimetype, filesize, account);
-
+
// 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;
}
-
+
private class UploaderRunnable implements Runnable {
-
+
Object mLock;
List<HashMap<String, Object>> mHashMapList;
-
+
public UploaderRunnable() {
mHashMapList = new LinkedList<HashMap<String, Object>>();
mLock = new Object();
}
-
- public void addElementToQueue(String filename,
- String filepath,
- String mimetype,
- long length,
- Account account) {
+
+ public void addElementToQueue(String filename, String filepath, String mimetype, long length, Account account) {
HashMap<String, Object> new_map = new HashMap<String, Object>();
new_map.put(KEY_ACCOUNT, account);
new_map.put(KEY_DISPLAY_NAME, filename);
new_map.put(KEY_FILE_PATH, filepath);
new_map.put(KEY_MIME_TYPE, mimetype);
new_map.put(KEY_FILE_SIZE, length);
-
+
synchronized (mLock) {
mHashMapList.add(new_map);
}
}
-
+
private HashMap<String, Object> getFirstObject() {
synchronized (mLock) {
if (mHashMapList.size() == 0)
return ret;
}
}
-
+
public void run() {
HashMap<String, Object> working_map;
-
+
while ((working_map = getFirstObject()) != null) {
Account account = (Account) working_map.get(KEY_ACCOUNT);
String filename = (String) working_map.get(KEY_DISPLAY_NAME);
String mimetype = (String) working_map.get(KEY_MIME_TYPE);
WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(account, getApplicationContext());
-
- wdc.createDirectory(INSTANT_UPLOAD_DIR); // fail could just mean that it already exists; put will be tried anyway
+
+ wdc.createDirectory(INSTANT_UPLOAD_DIR); // fail could just mean that it already exists put will be tried anyway
try {
- wdc.putFile(filepath, INSTANT_UPLOAD_DIR + "/" + filename, mimetype);
+ wdc.putFile(filepath, FileStorageUtils.getInstantUploadFilePath(filename), mimetype);
} catch (Exception e) {
// nothing to do; this service is deprecated, indeed
}
}
}
}
-
+
}
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PutMethod;
+import com.owncloud.android.Log_OC;
import com.owncloud.android.datamodel.OCFile;
+ import com.owncloud.android.network.ProgressiveDataTransferer;
import android.accounts.Account;
import android.util.Log;
File file = new File(getStoragePath());
raf = new RandomAccessFile(file, "r");
channel = raf.getChannel();
- ChunkFromFileChannelRequestEntity entity = new ChunkFromFileChannelRequestEntity(channel, getMimeType(), CHUNK_SIZE, file);
- entity.addOnDatatransferProgressListeners(getDataTransferListeners());
+ mEntity = new ChunkFromFileChannelRequestEntity(channel, getMimeType(), CHUNK_SIZE, file);
+ ((ProgressiveDataTransferer)mEntity).addDatatransferProgressListeners(getDataTransferListeners());
long offset = 0;
String uriPrefix = client.getBaseUri() + WebdavUtils.encodePath(getRemotePath()) + "-chunking-" + Math.abs((new Random()).nextInt(9000)+1000) + "-" ;
long chunkCount = (long) Math.ceil((double)file.length() / CHUNK_SIZE);
for (int chunkIndex = 0; chunkIndex < chunkCount ; chunkIndex++, offset += CHUNK_SIZE) {
mPutMethod = new PutMethod(uriPrefix + chunkCount + "-" + chunkIndex);
mPutMethod.addRequestHeader(OC_CHUNKED_HEADER, OC_CHUNKED_HEADER);
- entity.setOffset(offset);
- mPutMethod.setRequestEntity(entity);
+ ((ChunkFromFileChannelRequestEntity)mEntity).setOffset(offset);
+ 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;
}
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;
.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) {
public void addDatatransferProgressListener (OnDatatransferProgressListener listener) {
- mDataTransferListeners.add(listener);
+ synchronized (mDataTransferListeners) {
+ mDataTransferListeners.add(listener);
+ }
}
+ public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
+ synchronized (mDataTransferListeners) {
+ mDataTransferListeners.remove(listener);
+ }
+ }
+
@Override
protected RemoteOperationResult run(WebdavClient client) {
RemoteOperationResult result = null;
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;
}
fos.write(bytes, 0, readResult);
transferred += readResult;
- it = mDataTransferListeners.iterator();
- while (it.hasNext()) {
- it.next().onTransferProgress(readResult, transferred, mFile.getFileLength(), targetFile.getName());
+ synchronized (mDataTransferListeners) {
+ it = mDataTransferListeners.iterator();
+ while (it.hasNext()) {
+ it.next().onTransferProgress(readResult, transferred, mFile.getFileLength(), targetFile.getName());
+ }
}
}
savedFile = true;
mCancellationRequested.set(true); // atomic set; there is no need of synchronizing it
}
+
}
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;
}
- 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_OC.e(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() + ": " + result.getLogMessage(), result.getException());
- 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)
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PutMethod;
+ import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.http.HttpStatus;
-import android.util.Log;
+import com.owncloud.android.Log_OC;
+ import android.accounts.Account;
+
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.files.services.FileUploader;
+ import com.owncloud.android.network.ProgressiveDataTransferer;
import com.owncloud.android.operations.RemoteOperation;
import com.owncloud.android.operations.RemoteOperationResult;
import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
import eu.alefzero.webdav.OnDatatransferProgressListener;
import eu.alefzero.webdav.WebdavClient;
import eu.alefzero.webdav.WebdavUtils;
- import android.accounts.Account;
- import android.util.Log;
/**
* Remote operation performing the upload of a file to an ownCloud server
* @author David A. Velasco
*/
public class UploadFileOperation extends RemoteOperation {
-
+
private static final String TAG = UploadFileOperation.class.getSimpleName();
private Account mAccount;
private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
+ protected RequestEntity mEntity = null;
+
public UploadFileOperation( Account account,
OCFile file,
throw new IllegalArgumentException("Illegal NULL account in UploadFileOperation creation");
if (file == null)
throw new IllegalArgumentException("Illegal NULL file in UploadFileOperation creation");
- if (file.getStoragePath() == null || file.getStoragePath().length() <= 0 || !(new File(file.getStoragePath()).exists())) {
- throw new IllegalArgumentException("Illegal file in UploadFileOperation; storage path invalid or file not found: " + file.getStoragePath());
+ if (file.getStoragePath() == null || file.getStoragePath().length() <= 0
+ || !(new File(file.getStoragePath()).exists())) {
+ throw new IllegalArgumentException(
+ "Illegal file in UploadFileOperation; storage path invalid or file not found: "
+ + file.getStoragePath());
}
-
+
mAccount = account;
mFile = file;
mRemotePath = file.getRemotePath();
mOriginalFileName = mFile.getFileName();
}
-
public Account getAccount() {
return mAccount;
}
-
+
public String getFileName() {
return mOriginalFileName;
}
-
+
public OCFile getFile() {
return mFile;
}
-
+
public OCFile getOldFile() {
- return mOldFile;
+ return mOldFile;
}
-
+
public String getOriginalStoragePath() {
return mOriginalStoragePath;
}
-
+
public String getStoragePath() {
return mFile.getStoragePath();
}
public String getRemotePath() {
- return mFile.getRemotePath();
+ return mFile.getRemotePath();
}
public String getMimeType() {
return mFile.getMimetype();
}
-
+
public boolean isInstant() {
return mIsInstant;
}
public boolean isRemoteFolderToBeCreated() {
return mRemoteFolderToBeCreated;
}
-
+
public void setRemoteFolderToBeCreated() {
mRemoteFolderToBeCreated = true;
}
public boolean getForceOverwrite() {
return mForceOverwrite;
}
-
+
public boolean wasRenamed() {
return mWasRenamed;
}
-
+
public Set<OnDatatransferProgressListener> getDataTransferListeners() {
return mDataTransferListeners;
}
public void addDatatransferProgressListener (OnDatatransferProgressListener listener) {
- mDataTransferListeners.add(listener);
+ synchronized (mDataTransferListeners) {
+ mDataTransferListeners.add(listener);
+ }
+ if (mEntity != null) {
+ ((ProgressiveDataTransferer)mEntity).addDatatransferProgressListener(listener);
+ }
}
+ public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
+ synchronized (mDataTransferListeners) {
+ mDataTransferListeners.remove(listener);
+ }
+ if (mEntity != null) {
+ ((ProgressiveDataTransferer)mEntity).removeDatatransferProgressListener(listener);
+ }
+ }
+
@Override
protected RemoteOperationResult run(WebdavClient client) {
RemoteOperationResult result = null;
boolean localCopyPassed = false, nameCheckPassed = false;
File temporalFile = null, originalFile = new File(mOriginalStoragePath), expectedFile = null;
try {
- /// rename the file to upload, if necessary
+ // / rename the file to upload, if necessary
if (!mForceOverwrite) {
String remotePath = getAvailableRemotePath(client, mRemotePath);
mWasRenamed = !remotePath.equals(mRemotePath);
if (mWasRenamed) {
- createNewOCFile(remotePath);
+ createNewOCFile(remotePath);
}
}
nameCheckPassed = true;
-
- String expectedPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile); /// not before getAvailableRemotePath() !!!
+
+ String expectedPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile); // /
+ // not
+ // before
+ // getAvailableRemotePath()
+ // !!!
expectedFile = new File(expectedPath);
-
- /// check location of local file; if not the expected, copy to a temporal file before upload (if COPY is the expected behaviour)
+
+ // / check location of local file; if not the expected, copy to a
+ // temporal file before upload (if COPY is the expected behaviour)
if (!mOriginalStoragePath.equals(expectedPath) && mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_COPY) {
if (FileStorageUtils.getUsableSpace(mAccount.name) < originalFile.length()) {
result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_FULL);
- return result; // error condition when the file should be copied
-
+ return result; // error condition when the file should be
+ // copied
+
} else {
String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath();
mFile.setStoragePath(temporalPath);
temporalFile = new File(temporalPath);
- if (!mOriginalStoragePath.equals(temporalPath)) { // preventing weird but possible situation
+ if (!mOriginalStoragePath.equals(temporalPath)) { // preventing
+ // weird
+ // but
+ // possible
+ // situation
InputStream in = null;
OutputStream out = null;
try {
temporalFile.createNewFile();
if (!temporalFile.isFile()) {
throw new IOException("Unexpected error: target file could not be created");
- }
+ }
in = new FileInputStream(originalFile);
out = new FileOutputStream(temporalFile);
byte[] buf = new byte[1024];
int len;
- while ((len = in.read(buf)) > 0){
+ while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
-
+
} catch (Exception e) {
result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_COPIED);
return result;
-
+
} finally {
try {
- if (in != null) in.close();
+ 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();
+ 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);
}
}
}
}
}
localCopyPassed = true;
-
- /// perform the upload
- synchronized(mCancellationRequested) {
+
+ // / perform the upload
+ synchronized (mCancellationRequested) {
if (mCancellationRequested.get()) {
throw new OperationCancelledException();
} else {
}
}
int status = uploadFile(client);
-
-
- /// move local temporal file or original file to its corresponding location in the ownCloud local folder
+
+ // / move local temporal file or original file to its corresponding
+ // location in the ownCloud local folder
if (isSuccess(status)) {
if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_FORGET) {
mFile.setStoragePath(null);
-
+
} else {
mFile.setStoragePath(expectedPath);
File fileToMove = null;
- if (temporalFile != null) { // FileUploader.LOCAL_BEHAVIOUR_COPY ; see where temporalFile was set
+ if (temporalFile != null) { // FileUploader.LOCAL_BEHAVIOUR_COPY
+ // ; see where temporalFile was
+ // set
fileToMove = temporalFile;
- } else { // FileUploader.LOCAL_BEHAVIOUR_MOVE
+ } else { // FileUploader.LOCAL_BEHAVIOUR_MOVE
fileToMove = originalFile;
}
if (!expectedFile.equals(fileToMove)) {
expectedFolder.mkdirs();
if (!expectedFolder.isDirectory() || !fileToMove.renameTo(expectedFile)) {
mFile.setStoragePath(null); // forget the local file
- // by now, treat this as a success; the file was uploaded; the user won't like that the local file is not linked, but this should be a veeery rare fail;
- // the best option could be show a warning message (but not a fail)
- //result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_MOVED);
- //return result;
+ // by now, treat this as a success; the file was
+ // uploaded; the user won't like that the local file
+ // is not linked, but this should be a very rare
+ // fail;
+ // the best option could be show a warning message
+ // (but not a fail)
+ // result = new
+ // RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_MOVED);
+ // return result;
}
}
- }
+ }
}
-
+
result = new RemoteOperationResult(isSuccess(status), status);
-
-
+
} catch (Exception e) {
// TODO something cleaner with cancellations
if (mCancellationRequested.get()) {
} else {
result = new RemoteOperationResult(e);
}
-
-
+
} finally {
if (temporalFile != null && !originalFile.equals(temporalFile)) {
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 = "";
if (!nameCheckPassed) {
complement = " (while checking file existence in server)";
} else if (!localCopyPassed) {
- complement = " (while copying local file to " + FileStorageUtils.getSavePath(mAccount.name) + ")";
+ 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());
}
}
}
-
+
return result;
}
-
private void createNewOCFile(String newRemotePath) {
// a new OCFile instance must be created for a new remote path
OCFile newFile = new OCFile(newRemotePath);
mFile = newFile;
}
-
public boolean isSuccess(int status) {
return ((status == HttpStatus.SC_OK || status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT));
}
-
-
+
protected int uploadFile(WebdavClient client) throws HttpException, IOException, OperationCancelledException {
int status = -1;
try {
File f = new File(mFile.getStoragePath());
- FileRequestEntity entity = new FileRequestEntity(f, getMimeType());
- entity.addOnDatatransferProgressListeners(mDataTransferListeners);
- mPutMethod.setRequestEntity(entity);
+ mEntity = new FileRequestEntity(f, getMimeType());
+ synchronized (mDataTransferListeners) {
+ ((ProgressiveDataTransferer)mEntity).addDatatransferProgressListeners(mDataTransferListeners);
+ }
+ mPutMethod.setRequestEntity(mEntity);
status = client.executeMethod(mPutMethod);
client.exhaustResponse(mPutMethod.getResponseBodyAsStream());
-
+
} finally {
- mPutMethod.releaseConnection(); // let the connection available for other methods
+ mPutMethod.releaseConnection(); // let the connection available for
+ // other methods
}
return status;
}
-
+
/**
- * Checks if remotePath does not exist in the server and returns it, or adds a suffix to it in order to avoid the server
- * file is overwritten.
+ * Checks if remotePath does not exist in the server and returns it, or adds
+ * a suffix to it in order to avoid the server file is overwritten.
*
* @param string
* @return
if (!check) {
return remotePath;
}
-
+
int pos = remotePath.lastIndexOf(".");
String suffix = "";
String extension = "";
if (pos >= 0) {
- extension = remotePath.substring(pos+1);
+ extension = remotePath.substring(pos + 1);
remotePath = remotePath.substring(0, pos);
}
int count = 2;
count++;
} while (check);
- if (pos >=0) {
+ if (pos >= 0) {
return remotePath + suffix + "." + extension;
} else {
return remotePath + suffix;
}
}
-
public void cancel() {
- synchronized(mCancellationRequested) {
+ synchronized (mCancellationRequested) {
mCancellationRequested.set(true);
if (mPutMethod != null)
mPutMethod.abort();
}
}
-
}
-/* 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 FileDetailFragment.ContainerActivity {
++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) {
- 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);
-
+ setContentView(R.layout.file_activity_details);
+
+ ActionBar actionBar = getSupportActionBar();
+ actionBar.setDisplayHomeAsUpEnabled(true);
+
- OCFile file = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);
- Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);
- FileDetailFragment mFileDetail = new FileDetailFragment(file, account);
-
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
- ft.replace(R.id.fragment, mFileDetail, FileDetailFragment.FTAG);
- ft.commit();
++ 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(); // the 'back' won't be effective until this.onStart() and this.onResume() are completed;
++ 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;
+ }
- FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
- if (fragment != null)
- fragment.updateFileDetails(false); // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais())
++
++ 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();
++ backToDisplayActivity(true);
+ returnValue = true;
+ break;
+ default:
- returnValue = super.onOptionsItemSelected(item);
++ returnValue = super.onOptionsItemSelected(item);
+ }
+
+ return returnValue;
+ }
+
-
-
- @Override
- protected void onResume() {
-
- super.onResume();
- if (!mConfigurationChangedToLandscape) {
- FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
- fragment.updateFileDetails(false);
- }
- }
-
-
- private void backToDisplayActivity() {
++ private void backToDisplayActivity(boolean moveToParent) {
+ Intent intent = new Intent(this, FileDisplayActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- intent.putExtra(FileDetailFragment.EXTRA_FILE, getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE));
- intent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT));
++ 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 )
++
++ }
++
+}
*
* 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
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
import android.accounts.Account;
import android.app.AlertDialog;
+ import android.app.ProgressDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
- import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
+ import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.View;
import 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;
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.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.syncadapter.FileSyncService;
import com.owncloud.android.ui.dialog.ChangelogDialog;
+ import com.owncloud.android.ui.dialog.EditNameDialog;
import com.owncloud.android.ui.dialog.SslValidatorDialog;
+ import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;
import com.owncloud.android.ui.fragment.FileDetailFragment;
+ import com.owncloud.android.ui.fragment.FileFragment;
import com.owncloud.android.ui.fragment.OCFileListFragment;
+ import com.owncloud.android.ui.preview.PreviewImageActivity;
+ import com.owncloud.android.ui.preview.PreviewImageFragment;
+ import com.owncloud.android.ui.preview.PreviewMediaFragment;
+ import com.owncloud.android.R;
import eu.alefzero.webdav.WebdavClient;
/**
* Displays, what files the user has available in his ownCloud.
*
* @author Bartek Przybylski
- *
+ * @author David A. Velasco
*/
- public class FileDisplayActivity extends SherlockFragmentActivity implements OCFileListFragment.ContainerActivity,
- FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, OnRemoteOperationListener {
-
+ public class FileDisplayActivity extends SherlockFragmentActivity implements
+ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNavigationListener, OnSslValidatorListener, OnRemoteOperationListener, EditNameDialogListener {
+
private ArrayAdapter<String> mDirectories;
private OCFile mCurrentDir = null;
private OCFile mCurrentFile = null;
private OCFileListFragment mFileList;
private boolean mDualPane;
+ private boolean mBackFromCreatingFirstAccount;
private static final int DIALOG_SETUP_ACCOUNT = 0;
private static final int DIALOG_CREATE_DIR = 1;
- private static final int DIALOG_ABOUT_APP = 2;
public static final int DIALOG_SHORT_WAIT = 3;
private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 4;
private static final int DIALOG_SSL_VALIDATOR = 5;
private static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;
private static final int ACTION_SELECT_MULTIPLE_FILES = 2;
- private static final int ACTION_SELECT_FAILED_INSTANT_UPLOAD = 2;
-
+
private static final String TAG = "FileDisplayActivity";
+ private static int[] mMenuIdentifiersToPatch = {R.id.action_about_app};
-
+ 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
- mCurrentDir = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE); // no check necessary, mCurrenDir == null if the parameter is not in the intent
Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);
- if (account != null)
- AccountUtils.setCurrentOwnCloudAccount(this, account.name);
+ if (account != null && AccountUtils.setCurrentOwnCloudAccount(this, account.name)) {
+ mCurrentDir = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);
+ }
/// Load of saved instance state: keep this always before initDataFromCurrentAccount()
if(savedInstanceState != null) {
// TODO - test if savedInstanceState should take precedence over file in the intent ALWAYS (now), NEVER, or SOME TIMES
mCurrentDir = savedInstanceState.getParcelable(FileDetailFragment.EXTRA_FILE);
+ mWaitingToPreview = (OCFile) savedInstanceState.getParcelable(FileDetailActivity.KEY_WAITING_TO_PREVIEW);
+
+ } else {
+ mWaitingToPreview = null;
}
if (!AccountUtils.accountsAreSetup(this)) {
/// no account available: FORCE ACCOUNT CREATION
mStorageManager = null;
createFirstAccount();
-
- } else { // / at least an account is available
-
- initDataFromCurrentAccount(); // it checks mCurrentDir and
- // mCurrentFile with the current
- // account
-
+
+ } else { /// at least an account is available
+
+ initDataFromCurrentAccount(); // it checks mCurrentDir and mCurrentFile with the current account
+
}
mUploadConnection = new ListServiceConnection();
// Drop-down navigation
mDirectories = new CustomArrayAdapter<String>(this, R.layout.sherlock_spinner_dropdown_item);
OCFile currFile = mCurrentDir;
- while (currFile != null && currFile.getFileName() != OCFile.PATH_SEPARATOR) {
+ while(mStorageManager != null && currFile != null && currFile.getFileName() != OCFile.PATH_SEPARATOR) {
mDirectories.add(currFile.getFileName());
currFile = mStorageManager.getFileById(currFile.getParentId());
}
mFileList = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
mDualPane = (findViewById(R.id.file_details_container) != null);
if (mDualPane) {
- initFileDetailsInDualPane();
+ if (savedInstanceState == null) initFileDetailsInDualPane();
+ } else {
+ // quick patchES to fix problem in turn from landscape to portrait, when a file is selected in the right pane
+ // TODO serious refactorization in activities and fragments providing file browsing and handling
+ if (mCurrentFile != null) {
+ onFileClick(mCurrentFile);
+ mCurrentFile = null;
+ }
+ Fragment rightPanel = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+ if (rightPanel != null) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.remove(rightPanel);
+ transaction.commit();
+ }
}
// Action bar setup
// show changelog, if needed
- showChangeLog();
+ //showChangeLog();
+ mBackFromCreatingFirstAccount = false;
- Log.d(getClass().toString(), "onCreate() end");
+ Log_OC.d(getClass().toString(), "onCreate() end");
}
startActivity(intent); // the new activity won't be created until this.onStart() and this.onResume() are finished;
}
-
+
/**
* Load of state dependent of the existence of an ownCloud account
*/
if (mDualPane && getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG) == null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (mCurrentFile != null) {
- transaction.replace(R.id.file_details_container,
- new FileDetailFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)),
- FileDetailFragment.FTAG); // empty FileDetailFragment
+ if (PreviewMediaFragment.canBePreviewed(mCurrentFile)) {
+ if (mCurrentFile.isDown()) {
+ transaction.replace(R.id.file_details_container, new PreviewMediaFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+ } else {
+ transaction.replace(R.id.file_details_container, new FileDetailFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+ mWaitingToPreview = mCurrentFile;
+ }
+ } else {
+ transaction.replace(R.id.file_details_container, new FileDetailFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+ }
mCurrentFile = null;
+
} else {
- transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null),
- FileDetailFragment.FTAG); // empty FileDetailFragment
+ transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment
}
transaction.commit();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getSherlock().getMenuInflater();
- inflater.inflate(R.menu.menu, menu);
+ 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;
switch (item.getItemId()) {
- case R.id.createDirectoryItem: {
- showDialog(DIALOG_CREATE_DIR);
- break;
- }
- case R.id.startSync: {
- startSynchronization();
- break;
- }
- case R.id.action_upload: {
- showDialog(DIALOG_CHOOSE_UPLOAD_SOURCE);
- break;
- }
- case R.id.action_settings: {
- Intent settingsIntent = new Intent(this, Preferences.class);
- startActivity(settingsIntent);
- break;
- }
- case android.R.id.home: {
- if (mCurrentDir != null && mCurrentDir.getParentId() != 0) {
- onBackPressed();
+ case R.id.action_create_dir: {
+ EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.uploader_info_dirname), "", this);
+ dialog.show(getSupportFragmentManager(), "createdirdialog");
+ break;
}
- break;
- }
- default:
- retval = super.onOptionsItemSelected(item);
+ case R.id.action_sync_account: {
+ startSynchronization();
+ break;
+ }
+ case R.id.action_upload: {
+ showDialog(DIALOG_CHOOSE_UPLOAD_SOURCE);
+ break;
+ }
+ case R.id.action_settings: {
+ Intent settingsIntent = new Intent(this, Preferences.class);
+ startActivity(settingsIntent);
+ break;
+ }
- case R.id.action_about_app: {
- showDialog(DIALOG_ABOUT_APP);
- break;
- }
+ case android.R.id.home: {
+ if(mCurrentDir != null && mCurrentDir.getParentId() != 0){
+ onBackPressed();
+ }
+ break;
+ }
+ default:
+ retval = super.onOptionsItemSelected(item);
}
return retval;
}
* Called, when the user selected something for uploading
*/
public void onActivityResult(int requestCode, int resultCode, Intent data) {
-
- if (requestCode == ACTION_SELECT_CONTENT_FROM_APPS
- && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
+
+ if (requestCode == ACTION_SELECT_CONTENT_FROM_APPS && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
requestSimpleUpload(data, resultCode);
-
- } else if (requestCode == ACTION_SELECT_MULTIPLE_FILES
- && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
+
+ } else if (requestCode == ACTION_SELECT_MULTIPLE_FILES && (resultCode == RESULT_OK || resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) {
requestMultipleUpload(data, resultCode);
}
}
if (!remotePathBase.endsWith(OCFile.PATH_SEPARATOR))
remotePathBase += OCFile.PATH_SEPARATOR;
- for (int j = 0; j < remotePaths.length; j++) {
+ for (int j = 0; j< remotePaths.length; j++) {
remotePaths[j] = remotePathBase + (new File(filePaths[j])).getName();
}
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;
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;
}
Intent i = new Intent(this, FileUploader.class);
- i.putExtra(FileUploader.KEY_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+ i.putExtra(FileUploader.KEY_ACCOUNT,
+ AccountUtils.getCurrentOwnCloudAccount(this));
String remotepath = new String();
for (int j = mDirectories.getCount() - 2; j >= 0; --j) {
remotepath += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);
mCurrentDir = mFileList.getCurrentFile();
if (mDualPane) {
- // Resets the FileDetailsFragment on Tablets so that it always
- // displays
- FileDetailFragment fileDetails = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(
- FileDetailFragment.FTAG);
- if (fileDetails != null && !fileDetails.isEmpty()) {
+ // Resets the FileDetailsFragment on Tablets so that it always displays
+ Fragment fileFragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+ if (fileFragment != null && (fileFragment instanceof PreviewMediaFragment || !((FileDetailFragment) fileFragment).isEmpty())) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
- transaction.remove(fileDetails);
- transaction.add(R.id.file_details_container, new FileDetailFragment(null, null),
- FileDetailFragment.FTAG);
+ transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment
transaction.commit();
}
}
-
- if (mCurrentDir.getParentId() == 0) {
- ActionBar actionBar = getSupportActionBar();
+
+ if(mCurrentDir.getParentId() == 0){
+ ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(false);
- }
+ }
}
@Override
protected void onSaveInstanceState(Bundle outState) {
// responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved
- Log.d(getClass().toString(), "onSaveInstanceState() start");
+ Log_OC.d(getClass().toString(), "onSaveInstanceState() start");
super.onSaveInstanceState(outState);
outState.putParcelable(FileDetailFragment.EXTRA_FILE, mCurrentDir);
if (mDualPane) {
- FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+ FileFragment fragment = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
if (fragment != null) {
- OCFile file = fragment.getDisplayedFile();
+ OCFile file = fragment.getFile();
if (file != null) {
outState.putParcelable(FileDetailFragment.EXTRA_FILE, file);
}
}
}
- Log.d(getClass().toString(), "onSaveInstanceState() end");
+ outState.putParcelable(FileDetailActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
+ 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)) {
if (mDualPane) {
initFileDetailsInDualPane();
}
+ mBackFromCreatingFirstAccount = true;
}
// Listen for sync messages
registerReceiver(mUploadFinishReceiver, uploadIntentFilter);
// Listen for download messages
- IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_FINISH_MESSAGE);
+ IntentFilter downloadIntentFilter = new IntentFilter(FileDownloader.DOWNLOAD_ADDED_MESSAGE);
+ downloadIntentFilter.addAction(FileDownloader.DOWNLOAD_FINISH_MESSAGE);
mDownloadFinishReceiver = new DownloadFinishReceiver();
registerReceiver(mDownloadFinishReceiver, downloadIntentFilter);
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);
dismissDialog(DIALOG_SETUP_ACCOUNT);
}
- Log.d(getClass().toString(), "onPause() end");
+ Log_OC.d(getClass().toString(), "onPause() end");
}
dialog = builder.create();
break;
}
- case DIALOG_ABOUT_APP: {
- builder = new AlertDialog.Builder(this);
- builder.setTitle(getString(R.string.about_title));
- PackageInfo pkg;
- try {
- pkg = getPackageManager().getPackageInfo(getPackageName(), 0);
- builder.setMessage(String.format(getString(R.string.about_message), getString(R.string.app_name), pkg.versionName));
- builder.setIcon(android.R.drawable.ic_menu_info_details);
- dialog = builder.create();
- } catch (NameNotFoundException e) {
- builder = null;
- dialog = null;
- Log.e(TAG, "Error while showing about dialog", e);
- }
- break;
- }
case DIALOG_CREATE_DIR: {
builder = new Builder(this);
final EditText dirNameInput = new EditText(getBaseContext());
builder.setTitle(R.string.uploader_info_dirname);
int typed_color = getResources().getColor(R.color.setup_text_typed);
dirNameInput.setTextColor(typed_color);
- builder.setPositiveButton(android.R.string.ok, new OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- String directoryName = dirNameInput.getText().toString();
- if (directoryName.trim().length() == 0) {
- dialog.cancel();
- return;
- }
-
- // Figure out the path where the dir needs to be created
- String path;
- if (mCurrentDir == null) {
- // this is just a patch; we should ensure that
- // mCurrentDir never is null
- if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) {
- OCFile file = new OCFile(OCFile.PATH_SEPARATOR);
- mStorageManager.saveFile(file);
+ builder.setPositiveButton(android.R.string.ok,
+ new OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ String directoryName = dirNameInput.getText().toString();
+ if (directoryName.trim().length() == 0) {
+ dialog.cancel();
+ return;
+ }
+
+ // Figure out the path where the dir needs to be created
+ String path;
+ if (mCurrentDir == null) {
+ // this is just a patch; we should ensure that mCurrentDir never is null
+ if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) {
+ OCFile file = new OCFile(OCFile.PATH_SEPARATOR);
+ mStorageManager.saveFile(file);
+ }
+ mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);
+ }
+ path = FileDisplayActivity.this.mCurrentDir.getRemotePath();
+
+ // Create directory
+ path += directoryName + OCFile.PATH_SEPARATOR;
+ Thread thread = new Thread(new DirectoryCreator(path, AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), new Handler()));
+ thread.start();
+
+ dialog.dismiss();
+
+ showDialog(DIALOG_SHORT_WAIT);
}
- mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);
- }
- path = FileDisplayActivity.this.mCurrentDir.getRemotePath();
-
- // Create directory
- path += directoryName + OCFile.PATH_SEPARATOR;
- Thread thread = new Thread(new DirectoryCreator(path, AccountUtils
- .getCurrentOwnCloudAccount(FileDisplayActivity.this), new Handler()));
- thread.start();
-
- dialog.dismiss();
-
- showDialog(DIALOG_SHORT_WAIT);
- }
- });
- builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- dialog.cancel();
- }
- });
+ });
+ builder.setNegativeButton(R.string.common_cancel,
+ new OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
+ });
dialog = builder.create();
break;
}
case DIALOG_SHORT_WAIT: {
ProgressDialog working_dialog = new ProgressDialog(this);
- working_dialog.setMessage(getResources().getString(R.string.wait_a_moment));
+ working_dialog.setMessage(getResources().getString(
+ R.string.wait_a_moment));
working_dialog.setIndeterminate(true);
working_dialog.setCancelable(false);
dialog = working_dialog;
break;
}
case DIALOG_CHOOSE_UPLOAD_SOURCE: {
- final String[] items = { getString(R.string.actionbar_upload_files),
- getString(R.string.actionbar_upload_from_apps), getString(R.string.actionbar_failed_instant_upload) };
+
+ String[] items = null;
+
+ String[] allTheItems = { getString(R.string.actionbar_upload_files),
+ getString(R.string.actionbar_upload_from_apps),
+ getString(R.string.actionbar_failed_instant_upload) };
+
+ String[] commonItems = { getString(R.string.actionbar_upload_files),
+ getString(R.string.actionbar_upload_from_apps) };
+
+ if (InstantUploadActivity.IS_ENABLED)
+ items = allTheItems;
+ else
+ items = commonItems;
+
builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.actionbar_upload);
builder.setItems(items, new DialogInterface.OnClickListener() {
action = action.setType("*/*").addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(Intent.createChooser(action, getString(R.string.upload_chooser_title)),
ACTION_SELECT_CONTENT_FROM_APPS);
- } else if (item == 2) {
+ } else if (item == 2 && InstantUploadActivity.IS_ENABLED) {
Account account = AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this);
Intent action = new Intent(FileDisplayActivity.this, InstantUploadActivity.class);
action.putExtra(FileUploader.KEY_ACCOUNT, account);
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();
- };
- });
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ };
+ });
dialog = builder.create();
break;
}
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
if (cursor != null) {
- int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
+ int column_index = cursor
+ .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
- }
+ }
return null;
}
public void run() {
dismissDialog(DIALOG_SHORT_WAIT);
try {
- Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg,
- Toast.LENGTH_LONG);
+ Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG);
msg.show();
} catch (NotFoundException e) {
- Log.e(TAG, "Error while trying to show fail message " , e);
+ Log_OC.e(TAG, "Error while trying to show fail message ", e);
}
}
});
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);
-
- ((TextView) v).setTextColor(getResources().getColorStateList(android.R.color.white));
+
+ ((TextView) v).setTextColor(getResources().getColorStateList(
+ android.R.color.white));
return v;
}
-
- public View getDropDownView(int position, View convertView, ViewGroup parent) {
+
+ public View getDropDownView(int position, View convertView,
+ ViewGroup parent) {
View v = super.getDropDownView(position, convertView, parent);
-
- ((TextView) v).setTextColor(getResources().getColorStateList(android.R.color.white));
-
+
+ ((TextView) v).setTextColor(getResources().getColorStateList(
+ android.R.color.white));
+
return v;
}
*/
@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)) {
-
- String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH);
-
+ if (accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name)) {
+
+ String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH);
+
boolean fillBlankRoot = false;
if (mCurrentDir == null) {
mCurrentDir = mStorageManager.getFileByPath("/");
fillBlankRoot = (mCurrentDir != null);
}
- if ((synchFolderRemotePath != null && mCurrentDir != null && (mCurrentDir.getRemotePath()
- .equals(synchFolderRemotePath))) || fillBlankRoot) {
- if (!fillBlankRoot)
+ if ((synchFolderRemotePath != null && mCurrentDir != null && (mCurrentDir.getRemotePath().equals(synchFolderRemotePath)))
+ || fillBlankRoot ) {
+ if (!fillBlankRoot)
mCurrentDir = getStorageManager().getFileByPath(synchFolderRemotePath);
OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager()
.findFragmentById(R.id.fileList);
}
setSupportProgressBarIndeterminateVisibility(inProgress);
+ if (mBackFromCreatingFirstAccount) {
+ // awful patch to fix problem with visibility of progress circle with the first refresh of the first account
+ // TODO - kill this Activity when the first account has to be created instead of stack the account creation on it
+ getSupportActionBar().hide();
+ getSupportActionBar().show();
+ mBackFromCreatingFirstAccount = false;
+ }
removeStickyBroadcast(intent);
}
-
- RemoteOperationResult synchResult = (RemoteOperationResult) intent
- .getSerializableExtra(FileSyncService.SYNC_RESULT);
+
+ RemoteOperationResult synchResult = (RemoteOperationResult)intent.getSerializableExtra(FileSyncService.SYNC_RESULT);
if (synchResult != null) {
if (synchResult.getCode().equals(RemoteOperationResult.ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED)) {
mLastSslUntrustedServerResult = synchResult;
- showDialog(DIALOG_SSL_VALIDATOR);
+ showDialog(DIALOG_SSL_VALIDATOR);
}
}
}
String uploadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
String accountName = intent.getStringExtra(FileUploader.ACCOUNT_NAME);
boolean sameAccount = accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name);
- boolean isDescendant = (mCurrentDir != null) && (uploadedRemotePath != null)
- && (uploadedRemotePath.startsWith(mCurrentDir.getRemotePath()));
+ boolean isDescendant = (mCurrentDir != null) && (uploadedRemotePath != null) && (uploadedRemotePath.startsWith(mCurrentDir.getRemotePath()));
if (sameAccount && isDescendant) {
- OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager()
- .findFragmentById(R.id.fileList);
- if (fileListFragment != null) {
+ OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
+ if (fileListFragment != null) {
fileListFragment.listDirectory();
}
}
/**
- * Once the file download has finished -> update view
+ * Class waiting for broadcast events from the {@link FielDownloader} service.
+ *
+ * Updates the UI when a download is started or finished, provided that it is relevant for the
+ * current folder.
*/
private class DownloadFinishReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
+ boolean sameAccount = isSameAccount(context, intent);
String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
- String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
- boolean sameAccount = accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name);
- boolean isDescendant = (mCurrentDir != null) && (downloadedRemotePath != null)
- && (downloadedRemotePath.startsWith(mCurrentDir.getRemotePath()));
+ boolean isDescendant = isDescendant(downloadedRemotePath);
+
if (sameAccount && isDescendant) {
- OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager()
- .findFragmentById(R.id.fileList);
- if (fileListFragment != null) {
- fileListFragment.listDirectory();
+ updateLeftPanel();
+ if (mDualPane) {
+ updateRightPanel(intent.getAction(), downloadedRemotePath, intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false));
}
}
+
+ removeStickyBroadcast(intent);
+ }
+
+ private boolean isDescendant(String downloadedRemotePath) {
+ return (mCurrentDir != null && downloadedRemotePath != null && downloadedRemotePath.startsWith(mCurrentDir.getRemotePath()));
+ }
+
+ private boolean isSameAccount(Context context, Intent intent) {
+ String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
+ return (accountName != null && accountName.equals(AccountUtils.getCurrentOwnCloudAccount(context).name));
}
}
-
-
+ protected void updateLeftPanel() {
+ OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
+ if (fileListFragment != null) {
+ fileListFragment.listDirectory();
+ }
+ }
+
+ protected void updateRightPanel(String downloadEvent, String downloadedRemotePath, boolean success) {
+ Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+ boolean waitedPreview = (mWaitingToPreview != null && mWaitingToPreview.getRemotePath().equals(downloadedRemotePath));
+ if (fragment != null && fragment instanceof FileDetailFragment) {
+ FileDetailFragment detailsFragment = (FileDetailFragment) fragment;
+ OCFile fileInFragment = detailsFragment.getFile();
+ if (fileInFragment != null && !downloadedRemotePath.equals(fileInFragment.getRemotePath())) {
+ // the user browsed to other file ; forget the automatic preview
+ mWaitingToPreview = null;
+
+ } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_ADDED_MESSAGE)) {
+ // grant that the right panel updates the progress bar
+ detailsFragment.listenForTransferProgress();
+ detailsFragment.updateFileDetails(true, false);
+
+ } else if (downloadEvent.equals(FileDownloader.DOWNLOAD_FINISH_MESSAGE)) {
+ // update the right panel
+ if (success && waitedPreview) {
+ mWaitingToPreview = mStorageManager.getFileById(mWaitingToPreview.getFileId()); // update the file from database, for the local storage path
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.replace(R.id.file_details_container, new PreviewMediaFragment(mWaitingToPreview, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+ transaction.commit();
+ mWaitingToPreview = null;
+
+ } else {
+ detailsFragment.updateFileDetails(false, (success));
+ }
+ }
+ }
+ }
+
+
/**
* {@inheritDoc}
*/
return mStorageManager;
}
-
+
/**
* {@inheritDoc}
*/
if (mDualPane) {
// Resets the FileDetailsFragment on Tablets so that it always displays
- FileDetailFragment fileDetails = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
- if (fileDetails != null && !fileDetails.isEmpty()) {
+ Fragment fileFragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+ if (fileFragment != null && (fileFragment instanceof PreviewMediaFragment || !((FileDetailFragment) fileFragment).isEmpty())) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
- transaction.remove(fileDetails);
- transaction.add(R.id.file_details_container, new FileDetailFragment(null, null),
- FileDetailFragment.FTAG);
+ transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FileDetailFragment.FTAG); // empty FileDetailFragment
transaction.commit();
}
}
*/
@Override
public void onFileClick(OCFile file) {
-
- // If we are on a large device -> update fragment
+ if (file != null && PreviewImageFragment.canBePreviewed(file)) {
+ // preview image - it handles the download, if needed
+ startPreviewImage(file);
+
+ } else if (file != null && PreviewMediaFragment.canBePreviewed(file)) {
+ if (file.isDown()) {
+ // general preview
+ startMediaPreview(file);
+
+ } else {
+ // automatic download, preview on finish
+ startDownloadForPreview(file);
+
+ }
+ } else {
+ // details view
+ startDetails(file);
+ }
+ }
+
+ private void startPreviewImage(OCFile file) {
+ Intent showDetailsIntent = new Intent(this, PreviewImageActivity.class);
+ showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
+ showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+ startActivity(showDetailsIntent);
+ }
+
+ private void startMediaPreview(OCFile file) {
if (mDualPane) {
- // buttons in the details view are problematic when trying to reuse an existing fragment; create always a new one solves some of them, BUT no all; downloads are 'dangerous'
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
- transaction
- .replace(R.id.file_details_container,
- new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)),
- FileDetailFragment.FTAG);
- transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
+ transaction.replace(R.id.file_details_container, new PreviewMediaFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
transaction.commit();
-
- } else { // small or medium screen device -> new Activity
+
+ } else {
Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
}
}
+ private void startDownloadForPreview(OCFile file) {
+ if (mDualPane) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+ transaction.commit();
+ mWaitingToPreview = file;
+ requestForDownload();
+
+ } else {
+ Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+ showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
+ showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+ startActivity(showDetailsIntent);
+ }
+ }
+
+ private void startDetails(OCFile file) {
+ if (mDualPane && !file.isImage()) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+ transaction.commit();
+ } else {
+ Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+ showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
+ showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+ startActivity(showDetailsIntent);
+ }
+ }
+
+
/**
* {@inheritDoc}
*/
*/
@Override
public void onFileStateChanged() {
- OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(
- R.id.fileList);
- if (fileListFragment != null) {
+ OCFileListFragment fileListFragment = (OCFileListFragment) getSupportFragmentManager().findFragmentById(R.id.fileList);
+ if (fileListFragment != null) {
fileListFragment.listDirectory();
}
}
@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;
if (mFileList != null)
mFileList.listDirectory();
if (mDualPane) {
- FileDetailFragment fragment = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(
- FileDetailFragment.FTAG);
- if (fragment != null)
- fragment.updateFileDetails(false);
+ Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+ if (fragment != null && fragment instanceof FileDetailFragment) {
+ FileDetailFragment detailFragment = (FileDetailFragment)fragment;
+ detailFragment.listenForTransferProgress();
+ detailFragment.updateFileDetails(false, false);
+ }
}
}
@Override
public void onServiceDisconnected(ComponentName component) {
if (component.equals(new ComponentName(FileDisplayActivity.this, FileDownloader.class))) {
- Log.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;
}
}
startSynchronization();
}
+
@Override
public void onFailedSavingCertificate() {
showDialog(DIALOG_CERT_NOT_SAVED);
@Override
public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
if (operation instanceof RemoveFileOperation) {
- onRemoveFileOperationFinish((RemoveFileOperation) operation, result);
-
+ onRemoveFileOperationFinish((RemoveFileOperation)operation, result);
+
} else if (operation instanceof RenameFileOperation) {
- onRenameFileOperationFinish((RenameFileOperation) operation, result);
-
+ onRenameFileOperationFinish((RenameFileOperation)operation, result);
+
} else if (operation instanceof SynchronizeFileOperation) {
- onSynchronizeFileOperationFinish((SynchronizeFileOperation) operation, result);
+ onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);
}
}
msg.show();
OCFile removedFile = operation.getFile();
if (mDualPane) {
- FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(
- FileDetailFragment.FTAG);
- if (details != null && removedFile.equals(details.getDisplayedFile())) {
+ FileFragment details = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+ if (details != null && removedFile.equals(details.getFile())) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
- transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty
- // FileDetailFragment
+ transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null)); // empty FileDetailFragment
transaction.commit();
}
}
}
} else {
- Toast msg = Toast.makeText(this, R.string.remove_fail_msg, Toast.LENGTH_LONG);
+ Toast msg = Toast.makeText(this, R.string.remove_fail_msg, Toast.LENGTH_LONG);
msg.show();
if (result.isSslRecoverableException()) {
mLastSslUntrustedServerResult = result;
- showDialog(DIALOG_SSL_VALIDATOR);
+ showDialog(DIALOG_SSL_VALIDATOR);
}
}
}
OCFile renamedFile = operation.getFile();
if (result.isSuccess()) {
if (mDualPane) {
- FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(
- FileDetailFragment.FTAG);
- if (details != null && renamedFile.equals(details.getDisplayedFile())) {
- details.updateFileDetails(renamedFile, AccountUtils.getCurrentOwnCloudAccount(this));
+ FileFragment details = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+ if (details != null && details instanceof FileDetailFragment && renamedFile.equals(details.getFile()) ) {
+ ((FileDetailFragment) details).updateFileDetails(renamedFile, AccountUtils.getCurrentOwnCloudAccount(this));
}
}
if (mStorageManager.getFileById(renamedFile.getParentId()).equals(mCurrentDir)) {
} else {
if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {
- Toast msg = Toast.makeText(this, R.string.rename_local_fail_msg, Toast.LENGTH_LONG);
+ Toast msg = Toast.makeText(this, R.string.rename_local_fail_msg, Toast.LENGTH_LONG);
msg.show();
// TODO throw again the new rename dialog
} else {
- Toast msg = Toast.makeText(this, R.string.rename_server_fail_msg, Toast.LENGTH_LONG);
+ Toast msg = Toast.makeText(this, R.string.rename_server_fail_msg, Toast.LENGTH_LONG);
msg.show();
if (result.isSslRecoverableException()) {
mLastSslUntrustedServerResult = result;
- showDialog(DIALOG_SSL_VALIDATOR);
+ showDialog(DIALOG_SSL_VALIDATOR);
}
}
}
}
+
private void onSynchronizeFileOperationFinish(SynchronizeFileOperation operation, RemoteOperationResult result) {
dismissDialog(DIALOG_SHORT_WAIT);
OCFile syncedFile = operation.getLocalFile();
startActivity(i);
} else {
- Toast msg = Toast.makeText(this, R.string.sync_file_fail_msg, Toast.LENGTH_LONG);
+ Toast msg = Toast.makeText(this, R.string.sync_file_fail_msg, Toast.LENGTH_LONG);
msg.show();
}
onTransferStateChanged(syncedFile, true, true);
} else {
- Toast msg = Toast.makeText(this, R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG);
+ Toast msg = Toast.makeText(this, R.string.sync_file_nothing_to_do_msg, Toast.LENGTH_LONG);
msg.show();
}
}
fileListFragment.listDirectory();
}*/
if (mDualPane) {
- FileDetailFragment details = (FileDetailFragment) getSupportFragmentManager().findFragmentByTag(
- FileDetailFragment.FTAG);
- if (details != null && file.equals(details.getDisplayedFile())) {
+ FileFragment details = (FileFragment) getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);
+ if (details != null && details instanceof FileDetailFragment && file.equals(details.getFile()) ) {
if (downloading || uploading) {
- details.updateFileDetails(file, AccountUtils.getCurrentOwnCloudAccount(this));
+ ((FileDetailFragment)details).updateFileDetails(file, AccountUtils.getCurrentOwnCloudAccount(this));
} else {
- details.updateFileDetails(downloading || uploading);
+ ((FileDetailFragment)details).updateFileDetails(false, true);
}
}
}
}
-
+ @Override
+ public void showFragmentWithDetails(OCFile file) {
+ if (mDualPane) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);
+ transaction.commit();
+
+ } else {
+ Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
+ showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, file);
+ showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, AccountUtils.getCurrentOwnCloudAccount(this));
+ showDetailsIntent.putExtra(FileDetailActivity.EXTRA_MODE, FileDetailActivity.MODE_DETAILS);
+ startActivity(showDetailsIntent);
+ }
+ }
+ public void onDismiss(EditNameDialog dialog) {
+ //dialog.dismiss();
+ if (dialog.getResult()) {
+ String newDirectoryName = dialog.getNewFilename().trim();
+ Log.d(TAG, "'create directory' dialog dismissed with new name " + newDirectoryName);
+ if (newDirectoryName.length() > 0) {
+ String path;
+ if (mCurrentDir == null) {
+ // this is just a patch; we should ensure that mCurrentDir never is null
+ if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) {
+ OCFile file = new OCFile(OCFile.PATH_SEPARATOR);
+ mStorageManager.saveFile(file);
+ }
+ mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);
+ }
+ path = FileDisplayActivity.this.mCurrentDir.getRemotePath();
+
+ // Create directory
+ path += newDirectoryName + OCFile.PATH_SEPARATOR;
+ Thread thread = new Thread(new DirectoryCreator(path, AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), new Handler()));
+ thread.start();
+
+ showDialog(DIALOG_SHORT_WAIT);
+ }
+ }
+ }
+
+ private void requestForDownload() {
+ Account account = AccountUtils.getCurrentOwnCloudAccount(this);
+ if (!mDownloaderBinder.isDownloading(account, mWaitingToPreview)) {
+ Intent i = new Intent(this, FileDownloader.class);
+ i.putExtra(FileDownloader.EXTRA_ACCOUNT, account);
+ i.putExtra(FileDownloader.EXTRA_FILE, mWaitingToPreview);
+ startService(i);
+ }
+ }
+
}
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
+ import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageButton;
import android.widget.LinearLayout;
+ import android.widget.TextView;
import android.widget.Toast;
import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
import com.owncloud.android.R;
import com.owncloud.android.db.DbHandler;
import com.owncloud.android.files.InstantUploadBroadcastReceiver;
import com.owncloud.android.files.services.FileUploader;
- import com.owncloud.android.files.services.InstantUploadService;
+ import com.owncloud.android.utils.FileStorageUtils;
/**
* This Activity is used to display a list with images they could not be
* uploaded instantly. The images can be selected for delete or for a try again
* upload
*
- * The entrypoint for this activity is the 'Failed upload Notification" and a
- * submenue underneath the 'Upload' menuentry
+ * The entry-point for this activity is the 'Failed upload Notification" and a
+ * sub-menu underneath the 'Upload' menu-item
*
* @author andomaex / Matthias Baumann
*
private static final String LOG_TAG = InstantUploadActivity.class.getSimpleName();
private LinearLayout listView;
private static final String retry_chexbox_tag = "retry_chexbox_tag";
+ public static final boolean IS_ENABLED = false;
private static int MAX_LOAD_IMAGES = 5;
private int lastLoadImageIdx = 0;
private SparseArray<String> fileList = null;
+ CheckBox failed_upload_all_cb;
@Override
protected void onCreate(Bundle savedInstanceState) {
delete_all_btn.setOnClickListener(getDeleteListner());
Button retry_all_btn = (Button) findViewById(R.id.failed_upload_retry_all_btn);
retry_all_btn.setOnClickListener(getRetryListner());
- CheckBox failed_upload_all_cb = (CheckBox) findViewById(R.id.failed_upload_headline_cb);
+ this.failed_upload_all_cb = (CheckBox) findViewById(R.id.failed_upload_headline_cb);
failed_upload_all_cb.setOnCheckedChangeListener(getCheckAllListener());
listView = (LinearLayout) findViewById(R.id.failed_upload_scrollviewlayout);
lastLoadImageIdx++;
String imp_path = c.getString(1);
+ String message = c.getString(4);
fileList.put(lastLoadImageIdx, imp_path);
- LinearLayout rowLayout = getLinearLayout(lastLoadImageIdx);
+ LinearLayout rowLayout = getHorizontalLinearLayout(lastLoadImageIdx);
rowLayout.addView(getFileCheckbox(lastLoadImageIdx));
rowLayout.addView(getImageButton(imp_path, lastLoadImageIdx));
- rowLayout.addView(getFileButton(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;
}
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);
}
}
public void onClick(View v) {
try {
+
List<CheckBox> list = getCheckboxList();
for (CheckBox checkbox : list) {
boolean to_retry = checkbox.isChecked();
- Log.d(LOG_TAG, "Checkbox for " + checkbox.getId() + " was checked: " + to_retry);
+ 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);
}
// refresh the List
listView.removeAllViews();
loadListView(true);
+ if (failed_upload_all_cb != null) {
+ failed_upload_all_cb.setChecked(false);
+ }
}
}
@Override
public void onClick(View v) {
+
final DbHandler dbh = new DbHandler(getApplicationContext());
try {
List<CheckBox> list = getCheckboxList();
for (CheckBox checkbox : list) {
boolean to_be_delete = checkbox.isChecked();
- Log.d(LOG_TAG, "Checkbox for " + checkbox.getId() + " was checked: " + to_be_delete);
+ 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);
}
// refresh the List
listView.removeAllViews();
loadListView(true);
+ if (failed_upload_all_cb != null) {
+ failed_upload_all_cb.setChecked(false);
+ }
}
}
};
}
- private LinearLayout getLinearLayout(int id) {
+ private LinearLayout getHorizontalLinearLayout(int id) {
LinearLayout linearLayout = new LinearLayout(getApplicationContext());
linearLayout.setId(id);
linearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
return linearLayout;
}
- private Button getFileButton(final String img_path, int id) {
- Button retryButton = new Button(this);
+ private LinearLayout getVerticalLinearLayout() {
+ LinearLayout linearLayout = new LinearLayout(getApplicationContext());
+ linearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.MATCH_PARENT));
+ linearLayout.setGravity(Gravity.TOP);
+ linearLayout.setOrientation(LinearLayout.VERTICAL);
+ return linearLayout;
+ }
+
+ private View getFileButton(final String img_path, String message, int id) {
+
+ TextView failureTextView = new TextView(this);
+ failureTextView.setText(getString(R.string.failed_upload_failure_text) + message);
+ failureTextView.setBackgroundResource(R.color.owncloud_white);
+ failureTextView.setTextSize(8);
+ failureTextView.setOnLongClickListener(getOnLongClickListener(message));
+ failureTextView.setPadding(5, 5, 5, 10);
+ TextView retryButton = new TextView(this);
retryButton.setId(id);
retryButton.setText(img_path);
retryButton.setBackgroundResource(R.color.owncloud_white);
retryButton.setTextSize(8);
retryButton.setOnClickListener(getImageButtonOnClickListener(img_path));
- return retryButton;
+ retryButton.setOnLongClickListener(getOnLongClickListener(message));
+ retryButton.setPadding(5, 5, 5, 10);
+ LinearLayout verticalLayout = getVerticalLinearLayout();
+ verticalLayout.addView(retryButton);
+ verticalLayout.addView(failureTextView);
+
+ return verticalLayout;
+ }
+
+ private OnLongClickListener getOnLongClickListener(final String message) {
+ return new OnLongClickListener() {
+
+ @Override
+ public boolean onLongClick(View v) {
+ Log.d(LOG_TAG, message);
+ Toast toast = Toast.makeText(InstantUploadActivity.this, getString(R.string.failed_upload_retry_text)
+ + message, Toast.LENGTH_LONG);
+ toast.show();
+ return true;
+ }
+
+ };
}
private CheckBox getFileCheckbox(int id) {
// 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);
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;
*/
private void startUpload(String img_path) {
// extract filename
- String filename = img_path.substring(img_path.lastIndexOf('/'), img_path.length());
+ String filename = FileStorageUtils.getInstantUploadFilePath(img_path);
if (canInstantUpload()) {
Account account = AccountUtils.getCurrentOwnCloudAccount(InstantUploadActivity.this);
// add file again to upload queue
DbHandler db = new DbHandler(InstantUploadActivity.this);
try {
- db.updateFileState(img_path, DbHandler.UPLOAD_STATUS_UPLOAD_LATER);
+ db.updateFileState(img_path, DbHandler.UPLOAD_STATUS_UPLOAD_LATER, null);
} finally {
db.close();
}
Intent i = new Intent(InstantUploadActivity.this, FileUploader.class);
i.putExtra(FileUploader.KEY_ACCOUNT, account);
i.putExtra(FileUploader.KEY_LOCAL_FILE, img_path);
- i.putExtra(FileUploader.KEY_REMOTE_FILE, InstantUploadService.INSTANT_UPLOAD_DIR + "/" + filename);
+ i.putExtra(FileUploader.KEY_REMOTE_FILE, filename);
i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
i.putExtra(com.owncloud.android.files.services.FileUploader.KEY_INSTANT_UPLOAD, true);
final String msg = "try to upload file with name :" + filename;
- Log.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();
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;
/**
@Override
public void onCreate(Bundle savedInstanceState) {
- Log.d(TAG, "onCreate() start");
+ Log_OC.d(TAG, "onCreate() start");
super.onCreate(savedInstanceState);
if(savedInstanceState != null) {
mCurrentDialog = null;
}
- Log.d(TAG, "onCreate() end");
+ Log_OC.d(TAG, "onCreate() end");
}
@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");
}
String[] args = {getString(R.string.app_name)};
ConfirmationDialogFragment dialog = ConfirmationDialogFragment.newInstance(R.string.upload_query_move_foreign_files, args, R.string.common_yes, -1, R.string.common_no);
dialog.setOnConfirmationListener(UploadFilesActivity.this);
- mCurrentDialog = dialog;
- mCurrentDialog.show(getSupportFragmentManager(), QUERY_TO_MOVE_DIALOG_TAG);
+ dialog.show(getSupportFragmentManager(), QUERY_TO_MOVE_DIALOG_TAG);
}
}
}
@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();
setResult(RESULT_OK_AND_MOVE, data);
finish();
}
- mCurrentDialog.dismiss();
- mCurrentDialog = null;
}
@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);
- mCurrentDialog.dismiss();
- mCurrentDialog = null;
}
@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);
- mCurrentDialog.dismiss();
- mCurrentDialog = null;
}
import android.util.Log;
import com.actionbarsherlock.app.SherlockDialogFragment;
+import com.owncloud.android.Log_OC;
public class ConfirmationDialogFragment extends SherlockDialogFragment {
public final static String ARG_NEUTRAL_BTN_RES = "neutral_btn_res";
public final static String ARG_NEGATIVE_BTN_RES = "negative_btn_res";
+ public static final String FTAG_CONFIRMATION = "CONFIRMATION_FRAGMENT";
+
private ConfirmationDialogFragmentListener mListener;
/**
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;
}
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
mListener.onConfirmation(getTag());
+ dialog.dismiss();
}
});
if (neuBtn != -1)
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
mListener.onNeutral(getTag());
+ dialog.dismiss();
}
});
if (negBtn != -1)
@Override
public void onClick(DialogInterface dialog, int which) {
mListener.onCancel(getTag());
+ dialog.dismiss();
}
});
return builder.create();
-/* 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.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.FileDownloader;
+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.activity.TransferServiceGetter;
+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 {
++ OnClickListener,
++ ConfirmationDialogFragment.ConfirmationDialogFragmentListener, OnRemoteOperationListener, EditNameDialogListener,
++ FileFragment {
+
+ public static final String EXTRA_FILE = "FILE";
+ public static final String EXTRA_ACCOUNT = "ACCOUNT";
+
- private FileDetailFragment.ContainerActivity mContainerActivity;
++ private FileFragment.ContainerActivity mContainerActivity;
+
+ private int mLayout;
+ private View mView;
+ private OCFile mFile;
+ private Account mAccount;
+ private FileDataStorageManager mStorageManager;
- private ImageView mPreview;
+
- private DownloadFinishReceiver mDownloadFinishReceiver;
+ private UploadFinishReceiver mUploadFinishReceiver;
++ public ProgressListener mProgressListener;
+
+ private Handler mHandler;
+ private RemoteOperation mLastRemoteOperation;
- private DialogFragment mCurrentDialog;
-
++
+ 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);
- mPreview = (ImageView)mView.findViewById(R.id.fdPreview);
++ ProgressBar progressBar = (ProgressBar)mView.findViewById(R.id.fdProgressBar);
++ mProgressListener = new ProgressListener(progressBar);
+ }
+
- updateFileDetails(false);
++ 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());;
++ mStorageManager = new FileDataStorageManager(mAccount, getActivity().getApplicationContext().getContentResolver());
+ }
+ }
+
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
- Log_OC.i(getClass().toString(), "onSaveInstanceState() start");
+ super.onSaveInstanceState(outState);
+ outState.putParcelable(FileDetailFragment.EXTRA_FILE, mFile);
+ outState.putParcelable(FileDetailFragment.EXTRA_ACCOUNT, mAccount);
- Log_OC.i(getClass().toString(), "onSaveInstanceState() end");
+ }
+
++ @Override
++ public void onStart() {
++ super.onStart();
++ listenForTransferProgress();
++ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
-
- mDownloadFinishReceiver = new DownloadFinishReceiver();
- IntentFilter filter = new IntentFilter(
- FileDownloader.DOWNLOAD_FINISH_MESSAGE);
- getActivity().registerReceiver(mDownloadFinishReceiver, filter);
-
+ mUploadFinishReceiver = new UploadFinishReceiver();
- filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);
++ IntentFilter filter = new IntentFilter(FileUploader.UPLOAD_FINISH_MESSAGE);
+ getActivity().registerReceiver(mUploadFinishReceiver, filter);
-
- mPreview = (ImageView)mView.findViewById(R.id.fdPreview);
++
+ }
+
++
+ @Override
+ public void onPause() {
+ super.onPause();
-
- getActivity().unregisterReceiver(mDownloadFinishReceiver);
- mDownloadFinishReceiver = null;
-
- getActivity().unregisterReceiver(mUploadFinishReceiver);
- mUploadFinishReceiver = null;
-
- if (mPreview != null) {
- mPreview = null;
++ 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);
- setButtonsForTransferring(); // disable button immediately, although the synchronization does not result in a file transference
+
+ }
+ break;
+ }
+ case R.id.fdKeepInSync: {
+ CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync);
+ mFile.setKeepInSync(cb.isChecked());
+ 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);
- Log_OC.e(TAG, "starting observer service");
+ 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);
- mCurrentDialog = confDialog;
- mCurrentDialog.show(getFragmentManager(), FTAG_CONFIRMATION);
++ confDialog.show(getFragmentManager(), FTAG_CONFIRMATION);
+ break;
+ }
+ case R.id.fdOpenBtn: {
- 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_OC.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
- boolean toastIt = true;
- String mimeType = "";
- try {
- Intent i = new Intent(Intent.ACTION_VIEW);
- mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(storagePath.substring(storagePath.lastIndexOf('.') + 1));
- if (mimeType == null || !mimeType.equals(mFile.getMimetype())) {
- if (mimeType != null) {
- i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), mimeType);
- } else {
- // desperate try
- i.setDataAndType(Uri.parse("file://"+ encodedStoragePath), "*/*");
- }
- i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- startActivity(i);
- toastIt = false;
- }
-
- } catch (IndexOutOfBoundsException e) {
- Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
-
- } catch (ActivityNotFoundException e) {
- Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
-
- } catch (Throwable th) {
- Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
-
- } finally {
- if (toastIt) {
- Toast.makeText(getActivity(), "There is no application to handle file " + mFile.getFileName(), Toast.LENGTH_SHORT).show();
- }
- }
-
- }
++ 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);
+ }
+ }
- mCurrentDialog.dismiss();
- mCurrentDialog = null;
+ }
+
+ @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);
+ }
- mCurrentDialog.dismiss();
- mCurrentDialog = null;
+ }
+
+ @Override
+ public void onCancel(String callerTag) {
- Log_OC.d(TAG, "REMOVAL CANCELED");
- mCurrentDialog.dismiss();
- mCurrentDialog = null;
++ 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);
+ }
+
+
+ /**
- * Can be used to get the file that is currently being displayed.
- * @return The file on the screen.
++ * {@inheritDoc}
+ */
- public OCFile getDisplayedFile(){
++ 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);
++ 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) {
++ public void updateFileDetails(boolean transferring, boolean refresh) {
+
- if (mFile != null && mAccount != null && mLayout == R.layout.file_details_fragment) {
++ 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()) {
- // Update preview
- if (mFile.getMimetype().startsWith("image/")) {
- BitmapLoader bl = new BitmapLoader();
- bl.execute(new String[]{mFile.getStoragePath()});
- }
+
+ 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;
+ }
+
-
- /**
- * Interface to implement by any Activity that includes some instance of FileDetailFragment
- *
- * @author David A. Velasco
- */
- public interface ContainerActivity extends TransferServiceGetter {
-
- /**
- * Callback method invoked when the detail fragment wants to notice its container
- * activity about a relevant state the file shown by the fragment.
- *
- * Added to notify to FileDisplayActivity about the need of refresh the files list.
- *
- * Currently called when:
- * - a download is started;
- * - a rename is completed;
- * - a deletion is completed;
- * - the 'inSync' flag is changed;
- */
- public void onFileStateChanged();
-
- }
-
-
- /**
- * Once the file download has finished -> update view
- * @author Bartek Przybylski
- */
- private class DownloadFinishReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- String accountName = intent.getStringExtra(FileDownloader.ACCOUNT_NAME);
+
- if (!isEmpty() && accountName.equals(mAccount.name)) {
- boolean downloadWasFine = intent.getBooleanExtra(FileDownloader.EXTRA_DOWNLOAD_RESULT, false);
- String downloadedRemotePath = intent.getStringExtra(FileDownloader.EXTRA_REMOTE_PATH);
- if (mFile.getRemotePath().equals(downloadedRemotePath)) {
- if (downloadWasFine) {
- mFile = mStorageManager.getFileByPath(downloadedRemotePath);
- }
- updateFileDetails(false); // it updates the buttons; must be called although !downloadWasFine
- }
- }
- }
- }
-
-
+ /**
+ * 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); // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server
++ 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_OC.d("share", "sharing for version " + ocv.toString());
++ 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_OC.d("share", mPath+"");
++ 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_OC.d("sharer", ""+ url+"/");
++ Log.d("sharer", ""+ url+"/");
+
+ for (org.apache.commons.httpclient.Header a : find.getRequestHeaders()) {
- Log_OC.d("sharer-h", a.getName() + ":"+a.getValue());
++ Log.d("sharer-h", a.getName() + ":"+a.getValue());
+ }
+
+ int status2 = wc.executeMethod(find);
+
- Log_OC.d("sharer", "propstatus "+status2);
++ 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_OC.d("sharer", "getstatus "+status2);
- Log_OC.d("sharer", "" + get.getResponseBodyAsString());
++ Log.d("sharer", "getstatus "+status2);
++ Log.d("sharer", "" + get.getResponseBodyAsString());
+
+ for (org.apache.commons.httpclient.Header a : get.getResponseHeaders()) {
- Log_OC.d("sharer", a.getName() + ":"+a.getValue());
++ Log.d("sharer", a.getName() + ":"+a.getValue());
+ }
+
+ status = wc.executeMethod(post);
+ for (org.apache.commons.httpclient.Header a : post.getRequestHeaders()) {
- Log_OC.d("sharer-h", a.getName() + ":"+a.getValue());
++ Log.d("sharer-h", a.getName() + ":"+a.getValue());
+ }
+ for (org.apache.commons.httpclient.Header a : post.getResponseHeaders()) {
- Log_OC.d("sharer", a.getName() + ":"+a.getValue());
++ Log.d("sharer", a.getName() + ":"+a.getValue());
+ }
+ String resp = post.getResponseBodyAsString();
- Log_OC.d("share", ""+post.getURI().toString());
- Log_OC.d("share", "returned status " + status);
- Log_OC.d("share", " " +resp);
++ 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_OC.d("Actions:shareFile ok", "url: " + uri);
++ 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_OC.d(TAG, "name edit dialog dismissed with new name " + newFilename);
++ 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);
+ }
+ }
+
+
- class BitmapLoader extends AsyncTask<String, Void, Bitmap> {
- @SuppressLint({ "NewApi", "NewApi", "NewApi" }) // to avoid Lint errors since Android SDK r20
- @Override
- protected Bitmap doInBackground(String... params) {
- Bitmap result = null;
- if (params.length != 1) return result;
- String storagePath = params[0];
- try {
-
- BitmapFactory.Options options = new Options();
- options.inScaled = true;
- options.inPurgeable = true;
- options.inJustDecodeBounds = true;
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
- options.inPreferQualityOverSpeed = false;
- }
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
- options.inMutable = false;
- }
-
- result = BitmapFactory.decodeFile(storagePath, options);
- options.inJustDecodeBounds = false;
-
- int width = options.outWidth;
- int height = options.outHeight;
- int scale = 1;
- if (width >= 2048 || height >= 2048) {
- scale = (int) Math.ceil((Math.ceil(Math.max(height, width) / 2048.)));
- options.inSampleSize = scale;
- }
- Display display = getActivity().getWindowManager().getDefaultDisplay();
- Point size = new Point();
- int screenwidth;
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {
- display.getSize(size);
- screenwidth = size.x;
- } else {
- screenwidth = display.getWidth();
- }
-
- Log_OC.e("ASD", "W " + width + " SW " + screenwidth);
-
- if (width > screenwidth) {
- scale = (int) Math.ceil((float)width / screenwidth);
- options.inSampleSize = scale;
- }
-
- result = BitmapFactory.decodeFile(storagePath, options);
-
- Log_OC.e("ASD", "W " + options.outWidth + " SW " + options.outHeight);
-
- } catch (OutOfMemoryError e) {
- result = null;
- Log_OC.e(TAG, "Out of memory occured for file with size " + storagePath);
-
- } catch (NoSuchFieldError e) {
- result = null;
- Log_OC.e(TAG, "Error from access to unexisting field despite protection " + storagePath);
-
- } catch (Throwable t) {
- result = null;
- Log_OC.e(TAG, "Unexpected error while creating image preview " + storagePath, t);
- }
- return result;
- }
- @Override
- protected void onPostExecute(Bitmap result) {
- if (result != null && mPreview != null) {
- mPreview.setImageBitmap(result);
- }
- }
-
- }
-
+ /**
+ * {@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;
++ }
++
++ };
+
- }
++}
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;
private Handler mHandler;
private OCFile mTargetFile;
- private DialogFragment mCurrentDialog;
-
/**
* {@inheritDoc}
*/
*/
@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);
}
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");
}
}
} else {
- Log.d(TAG, "Null object in ListAdapter!!");
+ Log_OC.d(TAG, "Null object in ListAdapter!!");
}
}
public void onCreateContextMenu (ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getActivity().getMenuInflater();
- inflater.inflate(R.menu.file_context_menu, menu);
+ inflater.inflate(R.menu.file_actions_menu, menu);
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
OCFile targetFile = (OCFile) mAdapter.getItem(info.position);
List<Integer> toHide = new ArrayList<Integer>();
MenuItem item = null;
if (targetFile.isDirectory()) {
// contextual menu for folders
- toHide.add(R.id.open_file_item);
- toHide.add(R.id.download_file_item);
- toHide.add(R.id.cancel_download_item);
- toHide.add(R.id.cancel_upload_item);
+ toHide.add(R.id.action_open_file_with);
+ toHide.add(R.id.action_download_file);
+ toHide.add(R.id.action_cancel_download);
+ toHide.add(R.id.action_cancel_upload);
+ toHide.add(R.id.action_see_details);
if ( mContainerActivity.getFileDownloaderBinder().isDownloading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile) ||
mContainerActivity.getFileUploaderBinder().isUploading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile) ) {
- toDisable.add(R.id.rename_file_item);
- toDisable.add(R.id.remove_file_item);
+ toDisable.add(R.id.action_rename_file);
+ toDisable.add(R.id.action_remove_file);
}
} else {
// contextual menu for regular files
if (targetFile.isDown()) {
- toHide.add(R.id.cancel_download_item);
- toHide.add(R.id.cancel_upload_item);
- item = menu.findItem(R.id.download_file_item);
+ toHide.add(R.id.action_cancel_download);
+ toHide.add(R.id.action_cancel_upload);
+ item = menu.findItem(R.id.action_download_file);
if (item != null) {
item.setTitle(R.string.filedetails_sync_file);
}
} else {
- toHide.add(R.id.open_file_item);
+ toHide.add(R.id.action_open_file_with);
}
if ( mContainerActivity.getFileDownloaderBinder().isDownloading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile)) {
- toHide.add(R.id.download_file_item);
- toHide.add(R.id.cancel_upload_item);
- toDisable.add(R.id.open_file_item);
- toDisable.add(R.id.rename_file_item);
- toDisable.add(R.id.remove_file_item);
+ toHide.add(R.id.action_download_file);
+ toHide.add(R.id.action_cancel_upload);
+ toDisable.add(R.id.action_open_file_with);
+ toDisable.add(R.id.action_rename_file);
+ toDisable.add(R.id.action_remove_file);
} else if ( mContainerActivity.getFileUploaderBinder().isUploading(AccountUtils.getCurrentOwnCloudAccount(getActivity()), targetFile)) {
- toHide.add(R.id.download_file_item);
- toHide.add(R.id.cancel_download_item);
- toDisable.add(R.id.open_file_item);
- toDisable.add(R.id.rename_file_item);
- toDisable.add(R.id.remove_file_item);
+ toHide.add(R.id.action_download_file);
+ toHide.add(R.id.action_cancel_download);
+ toDisable.add(R.id.action_open_file_with);
+ toDisable.add(R.id.action_rename_file);
+ toDisable.add(R.id.action_remove_file);
} else {
- toHide.add(R.id.cancel_download_item);
- toHide.add(R.id.cancel_upload_item);
+ toHide.add(R.id.action_cancel_download);
+ toHide.add(R.id.action_cancel_upload);
}
}
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
mTargetFile = (OCFile) mAdapter.getItem(info.position);
switch (item.getItemId()) {
- case R.id.rename_file_item: {
+ case R.id.action_rename_file: {
EditNameDialog dialog = EditNameDialog.newInstance(getString(R.string.rename_dialog_title), mTargetFile.getFileName(), this);
dialog.show(getFragmentManager(), EditNameDialog.TAG);
return true;
}
- case R.id.remove_file_item: {
+ case R.id.action_remove_file: {
int messageStringId = R.string.confirmation_remove_alert;
int posBtnStringId = R.string.confirmation_remove_remote;
int neuBtnStringId = -1;
neuBtnStringId,
R.string.common_cancel);
confDialog.setOnConfirmationListener(this);
- mCurrentDialog = confDialog;
- mCurrentDialog.show(getFragmentManager(), FileDetailFragment.FTAG_CONFIRMATION);
+ confDialog.show(getFragmentManager(), FileDetailFragment.FTAG_CONFIRMATION);
return true;
}
- case R.id.open_file_item: {
+ case R.id.action_open_file_with: {
String storagePath = mTargetFile.getStoragePath();
String encodedStoragePath = WebdavUtils.encodePath(storagePath);
try {
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 {
}
} 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) {
}
return true;
}
- case R.id.download_file_item: {
+ case R.id.action_download_file: {
Account account = AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity());
RemoteOperation operation = new SynchronizeFileOperation(mTargetFile, null, mContainerActivity.getStorageManager(), account, true, false, getSherlockActivity());
WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(account, getSherlockActivity().getApplicationContext());
getSherlockActivity().showDialog(FileDisplayActivity.DIALOG_SHORT_WAIT);
return true;
}
- case R.id.cancel_download_item: {
+ case R.id.action_cancel_download: {
FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());
if (downloaderBinder != null && downloaderBinder.isDownloading(account, mTargetFile)) {
}
return true;
}
- case R.id.cancel_upload_item: {
+ case R.id.action_cancel_upload: {
FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());
if (uploaderBinder != null && uploaderBinder.isUploading(account, mTargetFile)) {
}
return true;
}
+ case R.id.action_see_details: {
+ ((FileFragment.ContainerActivity)getActivity()).showFragmentWithDetails(mTargetFile);
+ return true;
+ }
default:
return super.onContextItemSelected(item);
}
// 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());
}
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,
getActivity().showDialog(FileDisplayActivity.DIALOG_SHORT_WAIT);
}
- if (mCurrentDialog != null) {
- mCurrentDialog.dismiss();
- mCurrentDialog = null;
- }
}
}
mTargetFile.setStoragePath(null);
mContainerActivity.getStorageManager().saveFile(mTargetFile);
}
- if (mCurrentDialog != null) {
- mCurrentDialog.dismiss();
- mCurrentDialog = null;
- }
listDirectory();
mContainerActivity.onTransferStateChanged(mTargetFile, false, false);
}
@Override
public void onCancel(String callerTag) {
- Log.d(TAG, "REMOVAL CANCELED");
+ Log_OC.d(TAG, "REMOVAL CANCELED");
- if (mCurrentDialog != null) {
- mCurrentDialog.dismiss();
- mCurrentDialog = null;
- }
}
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.
*
* @author David A. Velasco
*/
- public class ChunkFromFileChannelRequestEntity implements RequestEntity {
+ public class ChunkFromFileChannelRequestEntity implements RequestEntity, ProgressiveDataTransferer {
private static final String TAG = ChunkFromFileChannelRequestEntity.class.getSimpleName();
return true;
}
- public void addOnDatatransferProgressListener(OnDatatransferProgressListener listener) {
- mDataTransferListeners.add(listener);
+ @Override
+ public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
+ synchronized (mDataTransferListeners) {
+ mDataTransferListeners.add(listener);
+ }
}
- public void addOnDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
- mDataTransferListeners.addAll(listeners);
+ @Override
+ public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
+ synchronized (mDataTransferListeners) {
+ mDataTransferListeners.addAll(listeners);
+ }
}
- public void removeOnDatatransferProgressListener(OnDatatransferProgressListener listener) {
- mDataTransferListeners.remove(listener);
+ @Override
+ public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
+ synchronized (mDataTransferListeners) {
+ mDataTransferListeners.remove(listener);
+ }
}
out.write(mBuffer.array(), 0, readCount);
mBuffer.clear();
mTransferred += readCount;
- it = mDataTransferListeners.iterator();
- while (it.hasNext()) {
- it.next().onTransferProgress(readCount, mTransferred, size, mFile.getName());
+ synchronized (mDataTransferListeners) {
+ it = mDataTransferListeners.iterator();
+ while (it.hasNext()) {
+ it.next().onTransferProgress(readCount, mTransferred, size, mFile.getName());
+ }
}
}
} 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);
}
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.
*
*/
- public class FileRequestEntity implements RequestEntity {
+ public class FileRequestEntity implements RequestEntity, ProgressiveDataTransferer {
final File mFile;
final String mContentType;
public boolean isRepeatable() {
return true;
}
-
- public void addOnDatatransferProgressListener(OnDatatransferProgressListener listener) {
- mDataTransferListeners.add(listener);
+
+ @Override
+ public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
+ synchronized (mDataTransferListeners) {
+ mDataTransferListeners.add(listener);
+ }
}
- public void addOnDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
- mDataTransferListeners.addAll(listeners);
+ @Override
+ public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
+ synchronized (mDataTransferListeners) {
+ mDataTransferListeners.addAll(listeners);
+ }
}
- public void removeOnDatatransferProgressListener(OnDatatransferProgressListener listener) {
- mDataTransferListeners.remove(listener);
+ @Override
+ public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
+ synchronized (mDataTransferListeners) {
+ mDataTransferListeners.remove(listener);
+ }
}
out.write(tmp.array(), 0, readResult);
tmp.clear();
transferred += readResult;
- it = mDataTransferListeners.iterator();
- while (it.hasNext()) {
- it.next().onTransferProgress(readResult, transferred, size, mFile.getName());
+ synchronized (mDataTransferListeners) {
+ it = mDataTransferListeners.iterator();
+ while (it.hasNext()) {
+ it.next().onTransferProgress(readResult, transferred, size, mFile.getName());
+ }
}
}
} 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 {
-/* 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.e(TAG, "DELETE of " + remoteFilePath + " finished with HTTP status " + status + (!ret?"(FAIL)":""));
++ 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.addOnDatatransferProgressListener(mDataTransferListener);
++ 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;
+ }
+
+}