Merge pull request #268 from owncloud/fix_fails_in_uploads_after_fall_and_rise_of_net...
authormasensio <masensio@solidgear.es>
Wed, 16 Oct 2013 12:26:02 +0000 (05:26 -0700)
committermasensio <masensio@solidgear.es>
Wed, 16 Oct 2013 12:26:02 +0000 (05:26 -0700)
Fix fails in uploads after fall and rise of network connection

16 files changed:
res/drawable-hdpi/icon.png
res/drawable-hdpi/logo.png
res/drawable-ldpi/icon.png
res/drawable-ldpi/logo.png
res/drawable-mdpi/icon.png
res/drawable-mdpi/logo.png
res/layout/media_control.xml
src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java
src/com/owncloud/android/files/services/FileUploader.java
src/com/owncloud/android/operations/ExistenceCheckOperation.java
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/fragment/FileDetailFragment.java
src/com/owncloud/android/ui/preview/PreviewImageActivity.java
src/com/owncloud/android/ui/preview/PreviewImageFragment.java
src/eu/alefzero/webdav/ChunkFromFileChannelRequestEntity.java
src/eu/alefzero/webdav/WebdavClient.java

index e388c7b..8a2fe19 100644 (file)
Binary files a/res/drawable-hdpi/icon.png and b/res/drawable-hdpi/icon.png differ
index ecea3b0..a920912 100644 (file)
Binary files a/res/drawable-hdpi/logo.png and b/res/drawable-hdpi/logo.png differ
index 11cf0ab..f8f54b7 100644 (file)
Binary files a/res/drawable-ldpi/icon.png and b/res/drawable-ldpi/icon.png differ
index 62dff25..7de7cb8 100644 (file)
Binary files a/res/drawable-ldpi/logo.png and b/res/drawable-ldpi/logo.png differ
index 6997c7e..42bbaad 100644 (file)
Binary files a/res/drawable-mdpi/icon.png and b/res/drawable-mdpi/icon.png differ
index ecea3b0..a920912 100644 (file)
Binary files a/res/drawable-mdpi/logo.png and b/res/drawable-mdpi/logo.png differ
index 489c997..f308edc 100644 (file)
@@ -27,7 +27,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="center"
-        android:paddingTop="4dip"
+        android:paddingTop="4dp"
         android:orientation="horizontal"
         >
 
             android:id="@+id/currentTimeText"
             android:textSize="14sp"
             android:textStyle="bold"
-            android:paddingTop="4dip"
-            android:paddingStart="4dip"
+            android:paddingTop="4dp"
+            android:paddingStart="4dp"
             android:layout_gravity="center_horizontal"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:paddingEnd="4dip"
+            android:paddingEnd="4dp"
             android:text="@string/placeholder_media_time"
             />
 
         <SeekBar
             android:id="@+id/progressBar"
             style="?android:attr/progressBarStyleHorizontal"
-            android:layout_width="0dip"
+            android:layout_width="0dp"
             android:layout_weight="1"
-            android:layout_height="32dip"
+            android:layout_height="32dp"
             android:layout_alignParentStart="true"
             android:layout_alignParentEnd="true" />
 
         <TextView android:id="@+id/totalTimeText"
             android:textSize="14sp"
             android:textStyle="bold"
-            android:paddingTop="4dip"
-            android:paddingEnd="4dip"
+            android:paddingTop="4dp"
+            android:paddingEnd="4dp"
             android:layout_gravity="center_horizontal"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:paddingStart="4dip"
+            android:paddingStart="4dp"
             android:text="@string/placeholder_media_time"
             />
         
index 6eb6ec7..fa8662f 100644 (file)
@@ -54,8 +54,7 @@ public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
         Log_OC.d(TAG, "Received: " + intent.getAction());
         if (intent.getAction().equals(android.net.ConnectivityManager.CONNECTIVITY_ACTION)) {
             handleConnectivityAction(context, intent);
-        } else if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH && 
-                intent.getAction().equals(NEW_PHOTO_ACTION_UNOFFICIAL)) {
+        }else if (intent.getAction().equals(NEW_PHOTO_ACTION_UNOFFICIAL)) {
             handleNewPhotoAction(context, intent);
             Log_OC.d(TAG, "UNOFFICIAL processed: com.android.camera.NEW_PICTURE");
         } else if (intent.getAction().equals(NEW_PHOTO_ACTION)) {
index 06d834f..aa7925d 100644 (file)
@@ -271,7 +271,8 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                 if (isInstant) {
                     newUpload.setRemoteFolderToBeCreated();
                 }
-                mPendingUploads.putIfAbsent(uploadKey, newUpload);
+                mPendingUploads.putIfAbsent(uploadKey, newUpload); // Grants that the file only upload once time
+
                 newUpload.addDatatransferProgressListener(this);
                 newUpload.addDatatransferProgressListener((FileUploaderBinder)mBinder);
                 requestedUploads.add(uploadKey);
@@ -721,12 +722,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         mNotification.contentView.setImageViewResource(R.id.status_icon, R.drawable.icon);
         
         /// includes a pending intent in the notification showing the details view of the file
-        Intent showDetailsIntent = null;
-        if (PreviewImageFragment.canBePreviewed(upload.getFile())) {
-            showDetailsIntent = new Intent(this, PreviewImageActivity.class);
-        } else {
-            showDetailsIntent = new Intent(this, FileDisplayActivity.class);
-        }
+        Intent showDetailsIntent = new Intent(this, FileDisplayActivity.class);
         showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, upload.getFile());
         showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, upload.getAccount());
         showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
index e404a6f..136fe22 100644 (file)
@@ -23,6 +23,7 @@ import org.apache.commons.httpclient.methods.HeadMethod;
 import com.owncloud.android.Log_OC;
 
 import eu.alefzero.webdav.WebdavClient;
+import eu.alefzero.webdav.WebdavUtils;
 import android.content.Context;
 import android.net.ConnectivityManager;
 
@@ -65,16 +66,16 @@ public class ExistenceCheckOperation extends RemoteOperation {
         RemoteOperationResult result = null;
         HeadMethod head = null;
         try {
-            head = new HeadMethod(client.getBaseUri() + mPath);
+            head = new HeadMethod(client.getBaseUri() + WebdavUtils.encodePath(mPath));
             int status = client.executeMethod(head, TIMEOUT, TIMEOUT);
             client.exhaustResponse(head.getResponseBodyAsStream());
             boolean success = (status == HttpStatus.SC_OK && !mSuccessIfAbsent) || (status == HttpStatus.SC_NOT_FOUND && mSuccessIfAbsent);
             result = new RemoteOperationResult(success, status, head.getResponseHeaders());
-            Log_OC.d(TAG, "Existence check for " + client.getBaseUri() + mPath + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + "finished with HTTP status " + status + (!success?"(FAIL)":""));
+            Log_OC.d(TAG, "Existence check for " + client.getBaseUri() + WebdavUtils.encodePath(mPath) + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + "finished with HTTP status " + status + (!success?"(FAIL)":""));
             
         } catch (Exception e) {
             result = new RemoteOperationResult(e);
-            Log_OC.e(TAG, "Existence check for " + client.getBaseUri() + mPath + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + ": " + result.getLogMessage(), result.getException());
+            Log_OC.e(TAG, "Existence check for " + client.getBaseUri() + WebdavUtils.encodePath(mPath) + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + ": " + result.getLogMessage(), result.getException());
             
         } finally {
             if (head != null)
index db47d46..284ece2 100644 (file)
@@ -86,6 +86,7 @@ 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.ui.preview.PreviewVideoActivity;
 
@@ -211,12 +212,15 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
 
             /// Check whether the 'main' OCFile handled by the Activity is contained in the current Account
             OCFile file = getFile();
+            // get parent from path
+            String parentPath = "";
             if (file != null) {
                 if (file.isDown() && file.getLastSyncDateForProperties() == 0) {
                     // upload in progress - right now, files are not inserted in the local cache until the upload is successful
-                    if (mStorageManager.getFileById(file.getParentId()) == null) {
-                        file = null;    // not able to know the directory where the file is uploading
-                    }
+                    // get parent from path
+                    parentPath = file.getRemotePath().substring(0, file.getRemotePath().lastIndexOf(file.getFileName()));
+                    if (mStorageManager.getFileByPath(parentPath) ==  null)
+                        file = null; // not able to know the directory where the file is uploading
                 } else {
                     file = mStorageManager.getFileByPath(file.getRemotePath());   // currentDir = null if not in the current Account
                 }
@@ -232,7 +236,9 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
                 if (fileIt.isDirectory()) {
                     mDirectories.add(fileIt.getFileName());
                 }
-                fileIt = mStorageManager.getFileById(fileIt.getParentId());
+                // get parent from path
+                parentPath = fileIt.getRemotePath().substring(0, fileIt.getRemotePath().lastIndexOf(fileIt.getFileName()));
+                fileIt = mStorageManager.getFileByPath(parentPath);
             }
             mDirectories.add(OCFile.PATH_SEPARATOR);
             if (!stateWasRecovered) {
@@ -855,7 +861,9 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
 
             Log_OC.d(TAG, "sync of account " + accountName + " is in_progress: " + inProgress);
 
-            if (getAccount() != null && accountName.equals(getAccount().name)) {  
+            if (getAccount() != null && accountName.equals(getAccount().name)
+                    && mStorageManager != null
+                    ) {  
 
                 String synchFolderRemotePath = intent.getStringExtra(FileSyncService.SYNC_FOLDER_REMOTE_PATH); 
 
@@ -869,7 +877,7 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
                 if ((synchFolderRemotePath != null && currentDir != null && (currentDir.getRemotePath().equals(synchFolderRemotePath)))
                         || fillBlankRoot ) {
                     if (!fillBlankRoot) 
-                        currentDir = getStorageManager().getFileByPath(synchFolderRemotePath);
+                        currentDir = mStorageManager.getFileByPath(synchFolderRemotePath);
                     OCFileListFragment fileListFragment = getListOfFilesFragment();
                     if (fileListFragment != null) {
                         fileListFragment.listDirectory(currentDir);
@@ -1358,7 +1366,8 @@ OCFileListFragment.ContainerActivity, FileDetailFragment.ContainerActivity, OnNa
             if (file.isDirectory()) {
                 return file;
             } else if (mStorageManager != null) {
-                return mStorageManager.getFileById(file.getParentId());
+                String parentPath = file.getRemotePath().substring(0, file.getRemotePath().lastIndexOf(file.getFileName()));
+                return mStorageManager.getFileByPath(parentPath);
             }
         }
         return null;
index 5380a88..d1269f5 100644 (file)
@@ -64,6 +64,7 @@ import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
 import com.owncloud.android.ui.dialog.EditNameDialog;
 import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
+import com.owncloud.android.ui.preview.PreviewImageFragment;
 
 import eu.alefzero.webdav.OnDatatransferProgressListener;
 
@@ -741,7 +742,13 @@ public class FileDetailFragment extends FileFragment implements
                         msg.show();
                     }
                     getSherlockActivity().removeStickyBroadcast(intent);    // not the best place to do this; a small refactorization of BroadcastReceivers should be done
+                    
                     updateFileDetails(false, false);    // it updates the buttons; must be called although !uploadWasFine; interrupted uploads still leave an incomplete file in the server
+                   
+                    // Force the preview if the file is an image
+                    if (uploadWasFine && PreviewImageFragment.canBePreviewed(getFile())) {
+                        ((FileDisplayActivity) mContainerActivity).startImagePreview(getFile());
+                    } 
                 }
             }
         }
index ef1e977..50cab7e 100644 (file)
@@ -16,8 +16,6 @@
  */
 package com.owncloud.android.ui.preview;
 
-import android.app.Dialog;
-import android.app.ProgressDialog;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -105,7 +103,10 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
     }
 
     private void initViewPager() {
-        OCFile parentFolder = mStorageManager.getFileById(getFile().getParentId());
+        // get parent from path
+        String parentPath = getFile().getRemotePath().substring(0, getFile().getRemotePath().lastIndexOf(getFile().getFileName()));
+        OCFile parentFolder = mStorageManager.getFileByPath(parentPath);
+        //OCFile parentFolder = mStorageManager.getFileById(getFile().getParentId());
         if (parentFolder == null) {
             // should not be necessary
             parentFolder = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);
@@ -153,7 +154,7 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
                     Log_OC.d(TAG, "Simulating reselection of current page after connection of download binder");
                     onPageSelected(mViewPager.getCurrentItem());
                 }
-                    
+
             } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) {
                 Log_OC.d(TAG, "Upload service connected");
                 mUploaderBinder = (FileUploaderBinder) service;
@@ -430,8 +431,12 @@ public class PreviewImageActivity extends FileActivity implements FileFragment.C
             if (!file.isImage()) {
                 throw new IllegalArgumentException("Non-image file passed as argument");
             }
-            mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver());
-            file = mStorageManager.getFileById(file.getFileId()); 
+            mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver());            
+            
+            // Update file according to DB file, if it is possible
+            if (file.getFileId() > DataStorageManager.ROOT_PARENT_ID)            
+                file = mStorageManager.getFileById(file.getFileId());
+            
             if (file != null) {
                 /// Refresh the activity according to the Account and OCFile set
                 setFile(file);  // reset after getting it fresh from mStorageManager
index 291bd4a..578c56e 100644 (file)
@@ -56,7 +56,6 @@ import com.owncloud.android.operations.OnRemoteOperationListener;
 import com.owncloud.android.operations.RemoteOperation;
 import com.owncloud.android.operations.RemoteOperationResult;
 import com.owncloud.android.operations.RemoveFileOperation;
-import com.owncloud.android.ui.activity.FileDisplayActivity;
 import com.owncloud.android.ui.fragment.ConfirmationDialogFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 
index 3f45396..103cd04 100644 (file)
@@ -120,11 +120,14 @@ public class ChunkFromFileChannelRequestEntity implements RequestEntity, Progres
             mChannel.position(mOffset);
             long size = mFile.length();
             if (size == 0) size = -1;
-            while (mChannel.position() < mOffset + mChunkSize && mChannel.position() < mChannel.size()) {
+            long maxCount = Math.min(mOffset + mChunkSize, mChannel.size());
+            while (mChannel.position() < maxCount) {
                 readCount = mChannel.read(mBuffer);
                 out.write(mBuffer.array(), 0, readCount);
                 mBuffer.clear();
-                mTransferred += readCount;
+                if (mTransferred < maxCount) {  // condition to avoid accumulate progress for repeated chunks
+                    mTransferred += readCount;
+                }
                 synchronized (mDataTransferListeners) {
                     it = mDataTransferListeners.iterator();
                     while (it.hasNext()) {
index cedf926..f25e390 100644 (file)
@@ -24,12 +24,14 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.Header;
 import org.apache.commons.httpclient.HttpClient;
 import org.apache.commons.httpclient.HttpConnectionManager;
 import org.apache.commons.httpclient.HttpException;
 import org.apache.commons.httpclient.HttpMethod;
 import org.apache.commons.httpclient.HttpMethodBase;
 import org.apache.commons.httpclient.HttpVersion;
+import org.apache.commons.httpclient.URI;
 import org.apache.commons.httpclient.UsernamePasswordCredentials;
 import org.apache.commons.httpclient.auth.AuthPolicy;
 import org.apache.commons.httpclient.auth.AuthScope;
@@ -48,6 +50,8 @@ import com.owncloud.android.network.BearerCredentials;
 import android.net.Uri;
 
 public class WebdavClient extends HttpClient {
+    private static final int MAX_REDIRECTIONS_COUNT = 3;
+    
     private Uri mUri;
     private Credentials mCredentials;
     private boolean mFollowRedirects;
@@ -160,15 +164,39 @@ public class WebdavClient extends HttpClient {
     
     @Override
     public int executeMethod(HttpMethod method) throws IOException, HttpException {
+        boolean customRedirectionNeeded = false;
         try {
             method.setFollowRedirects(mFollowRedirects);
         } catch (Exception e) {
-            
+            if (mFollowRedirects) Log_OC.d(TAG, "setFollowRedirects failed for " + method.getName() + " method, custom redirection will be used");
+            customRedirectionNeeded = mFollowRedirects;
         }
         if (mSsoSessionCookie != null && mSsoSessionCookie.length() > 0) {
             method.setRequestHeader("Cookie", mSsoSessionCookie);
         }
-        return super.executeMethod(method);
+        int status = super.executeMethod(method);
+        int redirectionsCount = 0;
+        while (customRedirectionNeeded &&
+                redirectionsCount < MAX_REDIRECTIONS_COUNT &&
+                (   status == HttpStatus.SC_MOVED_PERMANENTLY || 
+                    status == HttpStatus.SC_MOVED_TEMPORARILY ||
+                    status == HttpStatus.SC_TEMPORARY_REDIRECT)
+                ) {
+            
+            Header location = method.getResponseHeader("Location");
+            if (location != null) {
+                Log_OC.d(TAG,  "Location to redirect: " + location.getValue());
+                method.setURI(new URI(location.getValue(), true));
+                status = super.executeMethod(method);
+                redirectionsCount++;
+                
+            } else {
+                Log_OC.d(TAG,  "No location to redirect!");
+                status = HttpStatus.SC_NOT_FOUND;
+            }
+        }
+        
+        return status;
     }