Added progress bar for file transfers in details view (untested)
authorDavid A. Velasco <dvelasco@solidgear.es>
Tue, 19 Feb 2013 12:28:01 +0000 (13:28 +0100)
committerDavid A. Velasco <dvelasco@solidgear.es>
Tue, 19 Feb 2013 12:28:01 +0000 (13:28 +0100)
16 files changed:
res/layout/file_details_fragment.xml
res/values/strings.xml
src/com/owncloud/android/files/services/FileDownloader.java
src/com/owncloud/android/files/services/FileUploader.java
src/com/owncloud/android/network/ProgressiveDataTransferer.java [new file with mode: 0644]
src/com/owncloud/android/operations/ChunkedUploadFileOperation.java
src/com/owncloud/android/operations/DownloadFileOperation.java
src/com/owncloud/android/operations/UploadFileOperation.java
src/com/owncloud/android/ui/activity/FileDetailActivity.java
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/dialog/IndeterminateProgressDialog.java
src/com/owncloud/android/ui/fragment/FileDetailFragment.java
src/com/owncloud/android/ui/fragment/FilePreviewFragment.java
src/eu/alefzero/webdav/ChunkFromFileChannelRequestEntity.java
src/eu/alefzero/webdav/FileRequestEntity.java
src/eu/alefzero/webdav/WebdavClient.java

index 135a864..b562937 100644 (file)
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:background="@color/owncloud_white" >
-
-    <ScrollView
-        android:id="@+id/fdScrollView"
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent" >
-
-        <RelativeLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content" >
-
-            <RelativeLayout
-                android:id="@+id/fdFileHeaderContainer"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="16dp"
-                android:layout_marginTop="4dp" >
-
-                <ImageView
-                    android:id="@+id/fdIcon"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:src="@drawable/file" />
-
-                <TextView
-                    android:id="@+id/fdFilename"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_centerVertical="true"
-                    android:layout_toRightOf="@+id/fdIcon"
-                    android:text="file.name"
-                    android:textAppearance="?android:attr/textAppearanceLarge" />
-            </RelativeLayout>
-
-            <RelativeLayout
-                android:id="@+id/fdDetailsContainer"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/fdFileHeaderContainer" >
-
-                <RelativeLayout
-                    android:id="@+id/fdLabelContainer"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_alignParentLeft="true"
-                    android:layout_alignParentTop="true"
-                    android:layout_marginLeft="16dp" >
-
-                    <TextView
-                        android:id="@+id/fdTypeLabel"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_marginTop="24dp"
-                        android:text="@string/filedetails_type"
-                        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-                    <TextView
-                        android:id="@+id/fdSizeLabel"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_below="@+id/fdTypeLabel"
-                        android:layout_marginTop="12dp"
-                        android:text="@string/filedetails_size"
-                        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-                    <TextView
-                        android:id="@+id/fdCreatedLabel"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_below="@+id/fdSizeLabel"
-                        android:layout_marginTop="12dp"
-                        android:text="@string/filedetails_created"
-                        android:visibility="gone"
-                        android:textAppearance="?android:attr/textAppearanceMedium" />
-                    
-                    <TextView
-                        android:id="@+id/fdModifiedLabel"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_below="@+id/fdCreatedLabel"
-                        android:layout_marginTop="12dp"
-                        android:text="@string/filedetails_modified"
-                        android:textAppearance="?android:attr/textAppearanceMedium" />
-                </RelativeLayout>
-
-                <RelativeLayout
-                    android:id="@+id/fdValueContainer"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_alignParentTop="true"
-                    android:layout_marginLeft="12dp"
-                    android:layout_toRightOf="@+id/fdLabelContainer" >
-
-                    <TextView
-                        android:id="@+id/fdType"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_marginTop="24dp"
-                        android:text="JPG Image"
-                        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-                    <TextView
-                        android:id="@+id/fdSize"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_below="@+id/fdType"
-                        android:layout_marginTop="12dp"
-                        android:text="389 KB"
-                        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-                    <TextView
-                        android:id="@+id/fdCreated"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_below="@+id/fdSize"
-                        android:layout_marginTop="12dp"
-                        android:visibility="gone"
-                        android:text="2012/05/18 12:23 PM"
-                        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-                    <TextView
-                        android:id="@+id/fdModified"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_below="@+id/fdCreated"
-                        android:layout_marginTop="12dp"
-                        android:text="2012/05/19 02:56 PM"
-                        android:textAppearance="?android:attr/textAppearanceMedium" />
-                </RelativeLayout>
-
-            </RelativeLayout>
-
-            <RelativeLayout
-                android:id="@+id/fdPreviewAndDL"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_below="@+id/fdDetailsContainer"
-                android:gravity="center_horizontal" >
-
-                <CheckBox
-                    android:id="@+id/fdKeepInSync"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_centerHorizontal="true"
-                    android:text="@string/fd_keep_in_sync" />
-
-                <LinearLayout
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_below="@id/fdKeepInSync"
-                    android:orientation="vertical" >
-
-                    <LinearLayout
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:gravity="center_horizontal" >
-
-                        <Button
-                            android:id="@+id/fdRemoveBtn"
-                            android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
-                            android:layout_marginTop="12dp"
-                            android:text="@string/common_remove" />
-
-                        <Button
-                            android:id="@+id/fdOpenBtn"
-                            android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
-                            android:layout_marginTop="12dp"
-                            android:text="@string/filedetails_open" />
-
-                    </LinearLayout>
-
-                    <LinearLayout
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:gravity="center_horizontal">
-
-                        <Button
-                            android:id="@+id/fdDownloadBtn"
-                            android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
-                            android:layout_marginTop="12dp"
-                            android:text="@string/filedetails_download" />
-
-                        <Button
-                            android:id="@+id/fdRenameBtn"
-                            android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
-                            android:layout_marginTop="12dp"
-                            android:text="@string/common_rename" />
-
-                    </LinearLayout>
-<!-- 
-                    <Button
-                        android:id="@+id/fdShareBtn"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_marginTop="12dp"
-                        android:text="@string/common_share" />
- -->
-
-                </LinearLayout>
-            </RelativeLayout>
-
-        </RelativeLayout>
-    </ScrollView>
-
-</RelativeLayout>
\ No newline at end of file
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+       android:id="@+id/fdScrollView"
+       android:layout_width="fill_parent"
+       android:layout_height="fill_parent" >
+
+       <RelativeLayout
+               android:layout_width="match_parent"
+               android:layout_height="wrap_content" >
+
+               <RelativeLayout
+                       android:id="@+id/fdFileHeaderContainer"
+                       android:layout_width="match_parent"
+                       android:layout_height="wrap_content"
+                       android:layout_marginLeft="16dp"
+                       android:layout_marginTop="4dp" >
+       
+                       <ImageView
+                               android:id="@+id/fdIcon"
+                               android:layout_width="wrap_content"
+                               android:layout_height="wrap_content"
+                               android:src="@drawable/file" />
+                               
+                       <TextView
+                           android:id="@+id/fdFilename"
+                           android:layout_width="wrap_content"
+                           android:layout_height="wrap_content"
+                           android:layout_centerVertical="true"
+                           android:layout_toRightOf="@+id/fdIcon"
+                           android:text="@string/placeholder_filename"
+                           android:textAppearance="?android:attr/textAppearanceLarge" />
+                       
+               </RelativeLayout>
+       
+               <RelativeLayout
+                       android:id="@+id/fdDetailsContainer"
+                       android:layout_width="match_parent"
+                       android:layout_height="wrap_content"
+                       android:layout_below="@id/fdFileHeaderContainer" >
+               
+                       <RelativeLayout
+                               android:id="@+id/fdLabelContainer"
+                               android:layout_width="wrap_content"
+                               android:layout_height="wrap_content"
+                               android:layout_alignParentLeft="true"
+                               android:layout_alignParentTop="true"
+                               android:layout_marginLeft="16dp" >
+                               
+                               <TextView
+                                       android:id="@+id/fdTypeLabel"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_marginTop="24dp"
+                                       android:text="@string/filedetails_type"
+                                       android:textAppearance="?android:attr/textAppearanceMedium" />
+                                       
+                               <TextView
+                                       android:id="@+id/fdSizeLabel"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_below="@+id/fdTypeLabel"
+                                       android:layout_marginTop="12dp"
+                                       android:text="@string/filedetails_size"
+                                       android:textAppearance="?android:attr/textAppearanceMedium" />
+                                       
+                               <TextView
+                                       android:id="@+id/fdCreatedLabel"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_below="@+id/fdSizeLabel"
+                                       android:layout_marginTop="12dp"
+                                       android:text="@string/filedetails_created"
+                                       android:visibility="gone"
+                                       android:textAppearance="?android:attr/textAppearanceMedium" />
+                                         
+                               <TextView
+                                       android:id="@+id/fdModifiedLabel"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_below="@+id/fdCreatedLabel"
+                                       android:layout_marginTop="12dp"
+                                       android:text="@string/filedetails_modified"
+                                       android:textAppearance="?android:attr/textAppearanceMedium" />
+                       </RelativeLayout>
+       
+                       <RelativeLayout
+                               android:id="@+id/fdValueContainer"
+                               android:layout_width="wrap_content"
+                               android:layout_height="wrap_content"
+                               android:layout_alignParentTop="true"
+                               android:layout_marginLeft="12dp"
+                               android:layout_toRightOf="@+id/fdLabelContainer" >
+                               
+                               <TextView
+                                       android:id="@+id/fdType"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_marginTop="24dp"
+                                       android:text="@string/placeholder_filetype"
+                                       android:textAppearance="?android:attr/textAppearanceMedium" />
+                                       
+                               <TextView
+                                       android:id="@+id/fdSize"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_below="@+id/fdType"
+                                       android:layout_marginTop="12dp"
+                                       android:text="@string/placeholder_filesize"
+                                       android:textAppearance="?android:attr/textAppearanceMedium" />
+                                       
+                               <TextView
+                                       android:id="@+id/fdCreated"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_below="@+id/fdSize"
+                                       android:layout_marginTop="12dp"
+                                       android:visibility="gone"
+                                       android:text="@string/placeholder_timestamp"
+                                       android:textAppearance="?android:attr/textAppearanceMedium" />
+                                       
+                               <TextView
+                                       android:id="@+id/fdModified"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_below="@+id/fdCreated"
+                                       android:layout_marginTop="12dp"
+                                       android:text="@string/placeholder_timestamp"
+                                       android:textAppearance="?android:attr/textAppearanceMedium" />
+               
+                       </RelativeLayout>
+       
+               </RelativeLayout>
+       
+               <RelativeLayout
+                       android:id="@+id/fdProgressAndControl"
+                       android:layout_width="match_parent"
+                       android:layout_height="wrap_content"
+                       android:layout_below="@+id/fdDetailsContainer"
+                       android:gravity="center_horizontal" 
+                       android:layout_margin="16dp"
+                       >
+                       
+                       <CheckBox
+                               android:id="@+id/fdKeepInSync"
+                               android:layout_width="wrap_content"
+                               android:layout_height="wrap_content"
+                               android:layout_centerHorizontal="true"
+                               android:text="@string/fd_keep_in_sync" />
+
+                       <LinearLayout
+                               android:layout_width="match_parent"
+                               android:layout_height="wrap_content"
+                               android:layout_below="@id/fdKeepInSync"
+                               android:orientation="vertical" >
+                               
+                       <TextView 
+                           android:id="@+id/fdProgressText" 
+                           android:layout_width="match_parent"
+                               android:layout_height="wrap_content" 
+                               android:text="@string/downloader_download_in_progress_ticker"
+                               />
+                       
+                       <ProgressBar android:id="@+id/fdProgressBar"
+                                       android:layout_width="match_parent" 
+                                       android:layout_height="wrap_content"
+                                       android:progressDrawable="@android:drawable/progress_horizontal"
+                                       android:indeterminate="false" 
+                                       android:indeterminateOnly="false" 
+                                       />
+                                                                                               
+                           <LinearLayout
+                                       android:layout_width="match_parent"
+                                       android:layout_height="wrap_content"
+                                       android:gravity="center_horizontal"
+                                       android:layout_marginTop="12dp"
+                                       >
+                                                               
+                                       <Button
+                                               android:id="@+id/fdDownloadBtn"
+                                               android:layout_width="0dp"
+                                               android:layout_height="wrap_content"
+                                               android:layout_weight="1"
+                                               android:text="@string/filedetails_download" />
+                                               
+                                       <Button
+                                               android:id="@+id/fdOpenBtn"
+                                               android:layout_width="0dp"
+                                               android:layout_height="wrap_content"
+                                               android:layout_weight="1"
+                                               android:text="@string/filedetails_open" />
+                                               
+                               </LinearLayout>
+               
+                               <LinearLayout
+                                       android:layout_width="match_parent"
+                                       android:layout_height="wrap_content"
+                                       android:gravity="center_horizontal"
+                                       android:layout_marginTop="12dp"
+                                       >
+                                       
+                                       <Button
+                                               android:id="@+id/fdRenameBtn"
+                                               android:layout_width="0dp"
+                                               android:layout_height="wrap_content"
+                                               android:layout_weight="1"
+                                               android:text="@string/common_rename" />
+                                               
+                                   <Button
+                                               android:id="@+id/fdRemoveBtn"
+                                               android:layout_width="0dp"
+                                               android:layout_height="wrap_content"
+                                               android:layout_weight="1"
+                                               android:text="@string/common_remove" />
+                                               
+                               </LinearLayout>
+       
+                       </LinearLayout>
+                       
+               </RelativeLayout>
+
+       </RelativeLayout>
+       
+</ScrollView>
index d3fbe15..45b4a30 100644 (file)
        <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="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="instant_upload_on_wifi">Upload pictures via WiFi only</string>
        <string name="instant_upload_path">/InstantUpload</string>
index 7872c36..5fd6665 100644 (file)
@@ -49,6 +49,7 @@ import android.os.Looper;
 import android.os.Message;\r
 import android.os.Process;\r
 import android.util.Log;\r
+import android.widget.ProgressBar;\r
 import android.widget.RemoteViews;\r
 \r
 import com.owncloud.android.R;\r
@@ -214,6 +215,55 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
                 }\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) return;\r
+            String targetKey = buildRemoteName(account, file);\r
+            DownloadFileOperation target = null;\r
+            synchronized (mPendingDownloads) {\r
+                if (!file.isDirectory()) {\r
+                    target = mPendingDownloads.get(targetKey);\r
+                } else {\r
+                    // nothing to do for directories, right now\r
+                }\r
+            }\r
+            if (target != null) {\r
+                target.addDatatransferProgressListener(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) return;\r
+            String targetKey = buildRemoteName(account, file);\r
+            DownloadFileOperation target = null;\r
+            synchronized (mPendingDownloads) {\r
+                if (!file.isDirectory()) {\r
+                    target = mPendingDownloads.get(targetKey);\r
+                } else {\r
+                    // nothing to do for directories, right now\r
+                }\r
+            }\r
+            if (target != null) {\r
+                target.removeDatatransferProgressListener(listener);\r
+            }\r
+        }\r
+        \r
     }\r
     \r
     \r
index 91c568a..8f68554 100644 (file)
@@ -34,6 +34,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.InstantUploadBroadcastReceiver;
 import com.owncloud.android.operations.ChunkedUploadFileOperation;
+import com.owncloud.android.operations.DownloadFileOperation;
 import com.owncloud.android.operations.RemoteOperationResult;
 import com.owncloud.android.operations.UploadFileOperation;
 import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
@@ -340,6 +341,32 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                 }
             }
         }
+
+
+        /**
+         * 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) return;
+            String targetKey = buildRemoteName(account, file);
+            UploadFileOperation target = null;
+            synchronized (mPendingUploads) {
+                if (!file.isDirectory()) {
+                    target = mPendingUploads.get(targetKey);
+                } else {
+                    // nothing to do for directories, right now
+                }
+            }
+            if (target != null) {
+                target.addDatatransferProgressListener(listener);
+            }
+        }
+        
+        
     }
     
     
diff --git a/src/com/owncloud/android/network/ProgressiveDataTransferer.java b/src/com/owncloud/android/network/ProgressiveDataTransferer.java
new file mode 100644 (file)
index 0000000..81a5f4c
--- /dev/null
@@ -0,0 +1,33 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.network;
+
+import java.util.Collection;
+
+import eu.alefzero.webdav.OnDatatransferProgressListener;
+
+public interface ProgressiveDataTransferer {
+
+    public void addDatatransferProgressListener (OnDatatransferProgressListener listener);
+    
+    public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners);
+
+    public void removeDatatransferProgressListener(OnDatatransferProgressListener listener);
+
+}
index 413a76e..5e4b591 100644 (file)
@@ -28,6 +28,7 @@ import org.apache.commons.httpclient.HttpException;
 import org.apache.commons.httpclient.methods.PutMethod;
 
 import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.network.ProgressiveDataTransferer;
 
 import android.accounts.Account;
 import android.util.Log;
@@ -61,16 +62,16 @@ public class ChunkedUploadFileOperation extends UploadFileOperation {
             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);
index d752b3c..6a9d7b6 100644 (file)
@@ -123,9 +123,17 @@ public class DownloadFileOperation extends RemoteOperation {
     
     
     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;
@@ -190,9 +198,11 @@ public class DownloadFileOperation extends RemoteOperation {
                     }
                     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;
@@ -221,4 +231,5 @@ public class DownloadFileOperation extends RemoteOperation {
         mCancellationRequested.set(true);   // atomic set; there is no need of synchronizing it
     }
 
+
 }
index fa5bf02..55871ea 100644 (file)
@@ -30,10 +30,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 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 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;
@@ -70,6 +72,8 @@ public class UploadFileOperation extends RemoteOperation {
     private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
     private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
 
+    protected RequestEntity mEntity = null;
+
     
     public UploadFileOperation( Account account,
                                 OCFile file,
@@ -152,7 +156,21 @@ public class UploadFileOperation extends RemoteOperation {
     }
     
     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
@@ -331,9 +349,11 @@ public class UploadFileOperation extends RemoteOperation {
         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());
             
index a36c972..1c7e78a 100644 (file)
@@ -17,6 +17,8 @@
  */\r
 package com.owncloud.android.ui.activity;\r
 \r
+import java.lang.ref.WeakReference;\r
+\r
 import android.accounts.Account;\r
 import android.app.Dialog;\r
 import android.app.ProgressDialog;\r
@@ -30,6 +32,7 @@ import android.os.IBinder;
 import android.support.v4.app.Fragment;\r
 import android.support.v4.app.FragmentTransaction;\r
 import android.util.Log;\r
+import android.widget.ProgressBar;\r
 \r
 import com.actionbarsherlock.app.ActionBar;\r
 import com.actionbarsherlock.app.SherlockFragmentActivity;\r
@@ -40,18 +43,18 @@ import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 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.fragment.FilePreviewFragment;\r
 \r
-import com.owncloud.android.AccountUtils;\r
 import com.owncloud.android.R;\r
 \r
+import eu.alefzero.webdav.OnDatatransferProgressListener;\r
+\r
 /**\r
  * This activity displays the details of a file like its name, its size and so\r
  * on.\r
  * \r
  * @author Bartek Przybylski\r
- * \r
+ * @author David A. Velasco\r
  */\r
 public class FileDetailActivity extends SherlockFragmentActivity implements FileDetailFragment.ContainerActivity {\r
     \r
@@ -62,11 +65,16 @@ public class FileDetailActivity extends SherlockFragmentActivity implements File
     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
+    private 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
+    public ProgressListener mProgressListener;\r
     \r
 \r
     @Override\r
@@ -91,7 +99,10 @@ public class FileDetailActivity extends SherlockFragmentActivity implements File
             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
         }  else {\r
@@ -100,8 +111,11 @@ public class FileDetailActivity extends SherlockFragmentActivity implements File
         \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
         OCFile file = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE);\r
         Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);\r
@@ -109,7 +123,13 @@ public class FileDetailActivity extends SherlockFragmentActivity implements File
         \r
         Fragment newFragment = null;\r
         if (FilePreviewFragment.canBePreviewed(file) && mode == MODE_PREVIEW) {\r
-            newFragment = new FilePreviewFragment(file, account);\r
+            if (file.isDown()) {\r
+                newFragment = new FilePreviewFragment(file, account);\r
+            \r
+            } else {\r
+                newFragment = new FileDetailFragment(file, account);\r
+                mWaitingToPreview = true;\r
+            }\r
             \r
         } else {\r
             newFragment = new FileDetailFragment(file, account);\r
@@ -120,24 +140,48 @@ public class FileDetailActivity extends SherlockFragmentActivity implements File
     }\r
     \r
 \r
+    @Override\r
+    protected void onSaveInstanceState(Bundle outState) {\r
+        outState.putBoolean(KEY_WAITING_TO_PREVIEW, mWaitingToPreview);\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
+            Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
+            FileDetailFragment detailsFragment = (FileDetailFragment) fragment;\r
+                \r
             if (component.equals(new ComponentName(FileDetailActivity.this, FileDownloader.class))) {\r
                 Log.d(TAG, "Download service connected");\r
                 mDownloaderBinder = (FileDownloaderBinder) service;\r
+                if (detailsFragment != null) {\r
+                    mProgressListener = new ProgressListener(detailsFragment.getProgressBar());\r
+                    mDownloaderBinder.addDatatransferProgressListener(\r
+                            mProgressListener, \r
+                            (Account) getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT), \r
+                            (OCFile) getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE)\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
+                if (detailsFragment != null) {\r
+                    mProgressListener = new ProgressListener(detailsFragment.getProgressBar());\r
+                    mUploaderBinder.addDatatransferProgressListener(\r
+                            mProgressListener, \r
+                            (Account) getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT), \r
+                            (OCFile) getIntent().getParcelableExtra(FileDetailFragment.EXTRA_FILE)\r
+                            );\r
+                }\r
             } else {\r
                 return;\r
             }\r
-            Fragment fragment = getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG);\r
-            if (fragment != null && fragment instanceof FileDetailFragment) {\r
-                ((FileDetailFragment) fragment).updateFileDetails(false);   // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais())\r
+            \r
+            if (detailsFragment != null) {\r
+                detailsFragment.updateFileDetails(false);   // let the fragment gets the mDownloadBinder through getDownloadBinder() (see FileDetailFragment#updateFileDetais())\r
             }\r
         }\r
 \r
@@ -153,6 +197,39 @@ public class FileDetailActivity extends SherlockFragmentActivity implements File
         }\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
+                }\r
+            }\r
+            mLastPercent = percent;\r
+        }\r
+\r
+    };\r
+    \r
 \r
     @Override\r
     public void onDestroy() {\r
index 5619caf..3a27a69 100644 (file)
@@ -293,7 +293,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         if (mDualPane && getSupportFragmentManager().findFragmentByTag(FileDetailFragment.FTAG) == null) {\r
             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
             if (mCurrentFile != null) {\r
-                if (FilePreviewFragment.canBePreviewed(mCurrentFile)) {\r
+                if (mCurrentFile.isDown() && FilePreviewFragment.canBePreviewed(mCurrentFile)) {\r
                     transaction.replace(R.id.file_details_container, new FilePreviewFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);\r
                 } else {\r
                     transaction.replace(R.id.file_details_container, new FileDetailFragment(mCurrentFile, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);\r
@@ -1027,7 +1027,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         if (mDualPane) {\r
             // buttons in the details view are problematic when trying to reuse an existing fragment; create always a new one solves some of them, BUT no all; downloads are 'dangerous'\r
             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\r
-            if (FilePreviewFragment.canBePreviewed(file)) {\r
+            if (file != null && file.isDown() && FilePreviewFragment.canBePreviewed(file)) {\r
                 transaction.replace(R.id.file_details_container, new FilePreviewFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);\r
             } else {\r
                 transaction.replace(R.id.file_details_container, new FileDetailFragment(file, AccountUtils.getCurrentOwnCloudAccount(this)), FileDetailFragment.FTAG);\r
index 4f9305b..ab7d055 100644 (file)
@@ -43,7 +43,7 @@ public class IndeterminateProgressDialog extends SherlockDialogFragment {
         dialog.setIndeterminate(true);
         
         /// set message
-        int messageId = getArguments().getInt(ARG_MESSAGE_ID, R.string.text_placeholder);
+        int messageId = getArguments().getInt(ARG_MESSAGE_ID, R.string.placeholder_sentence);
         dialog.setMessage(getString(messageId));
         
         /// set cancellation behavior
index 680c0b6..eca461c 100644 (file)
@@ -18,6 +18,7 @@
 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
@@ -65,10 +66,12 @@ import android.view.View.OnClickListener;
 import android.view.View.OnTouchListener;\r
 import android.view.ViewGroup;\r
 import android.webkit.MimeTypeMap;\r
+import android.webkit.WebView.FindListener;\r
 import android.widget.Button;\r
 import android.widget.CheckBox;\r
 import android.widget.ImageView;\r
 import android.widget.MediaController;\r
+import android.widget.ProgressBar;\r
 import android.widget.TextView;\r
 import android.widget.Toast;\r
 import android.widget.VideoView;\r
@@ -105,6 +108,8 @@ import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
 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
@@ -731,9 +736,23 @@ public class FileDetailFragment extends SherlockFragment implements
             ((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
@@ -746,6 +765,10 @@ public class FileDetailFragment extends SherlockFragment implements
             ((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
         }\r
     }\r
 \r
@@ -761,6 +784,10 @@ public class FileDetailFragment extends SherlockFragment implements
             ((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
         }\r
     }\r
     \r
@@ -1074,4 +1101,14 @@ public class FileDetailFragment extends SherlockFragment implements
     }\r
 \r
 \r
+    public ProgressBar getProgressBar() {\r
+        View v = getView();\r
+        if (v != null) {\r
+            return (ProgressBar) v.findViewById(R.id.fdProgressBar);\r
+        } else {\r
+            return null;\r
+        }\r
+    }\r
+\r
+\r
 }\r
index b4c1d43..e95c7d1 100644 (file)
@@ -1039,8 +1039,7 @@ public class FilePreviewFragment extends SherlockFragment implements
      * @return          'True' if the file can be handled by the fragment.
      */
     public static boolean canBePreviewed(OCFile file) {
-        return (file != null && file.isDown() && 
-                (file.isAudio() || file.isVideo() || file.isImage()));
+        return (file != null && (file.isAudio() || file.isVideo() || file.isImage()));
     }
 
     /**
index 1316315..7f15d8b 100644 (file)
@@ -30,6 +30,8 @@ import java.util.Set;
 
 import org.apache.commons.httpclient.methods.RequestEntity;
 
+import com.owncloud.android.network.ProgressiveDataTransferer;
+
 import eu.alefzero.webdav.OnDatatransferProgressListener;
 
 import android.util.Log;
@@ -40,7 +42,7 @@ import android.util.Log;
  * 
  * @author David A. Velasco
  */
-public class ChunkFromFileChannelRequestEntity implements RequestEntity {
+public class ChunkFromFileChannelRequestEntity implements RequestEntity, ProgressiveDataTransferer {
 
     private static final String TAG = ChunkFromFileChannelRequestEntity.class.getSimpleName();
     
@@ -90,16 +92,25 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity {
         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);
+        }
     }
     
     
@@ -116,9 +127,11 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity {
                 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());
+                    }
                 }
             }
             
index 292d88b..aa32a32 100644 (file)
@@ -31,6 +31,8 @@ import java.util.Set;
 
 import org.apache.commons.httpclient.methods.RequestEntity;
 
+import com.owncloud.android.network.ProgressiveDataTransferer;
+
 import eu.alefzero.webdav.OnDatatransferProgressListener;
 
 import android.util.Log;
@@ -40,7 +42,7 @@ 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;
@@ -69,17 +71,26 @@ public class FileRequestEntity implements RequestEntity {
     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);
+        }
     }
     
     
@@ -102,9 +113,11 @@ public class FileRequestEntity implements RequestEntity {
                 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());
+                    }
                 }
             }
             
index 61f1660..f34cb69 100644 (file)
@@ -165,7 +165,7 @@ public class WebdavClient extends HttpClient {
         try {\r
             File f = new File(localFile);\r
             FileRequestEntity entity = new FileRequestEntity(f, contentType);\r
-            entity.addOnDatatransferProgressListener(mDataTransferListener);\r
+            entity.addDatatransferProgressListener(mDataTransferListener);\r
             put.setRequestEntity(entity);\r
             status = executeMethod(put);\r
             \r