Merge branch 'develop' into share_password_support
[pub/Android/ownCloud.git] / src / com / owncloud / android / operations / DownloadFileOperation.java
1 /**
2 * ownCloud Android client application
3 *
4 * @author David A. Velasco
5 * @author masensio
6 * Copyright (C) 2015 ownCloud Inc.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2,
10 * as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 package com.owncloud.android.operations;
23
24 import java.io.File;
25 import java.util.HashSet;
26 import java.util.Iterator;
27 import java.util.Set;
28 import java.util.concurrent.atomic.AtomicBoolean;
29
30 import com.owncloud.android.datamodel.OCFile;
31 import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
32 import com.owncloud.android.lib.common.OwnCloudClient;
33 import com.owncloud.android.lib.common.operations.OperationCancelledException;
34 import com.owncloud.android.lib.common.operations.RemoteOperation;
35 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
36 import com.owncloud.android.lib.common.utils.Log_OC;
37 import com.owncloud.android.lib.resources.files.DownloadRemoteFileOperation;
38 import com.owncloud.android.utils.FileStorageUtils;
39
40 import android.accounts.Account;
41 import android.webkit.MimeTypeMap;
42
43 /**
44 * Remote mDownloadOperation performing the download of a file to an ownCloud server
45 */
46 public class DownloadFileOperation extends RemoteOperation {
47
48 private static final String TAG = DownloadFileOperation.class.getSimpleName();
49
50 private Account mAccount;
51 private OCFile mFile;
52 private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
53 private long mModificationTimestamp = 0;
54 private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
55
56 private DownloadRemoteFileOperation mDownloadOperation;
57
58
59 public DownloadFileOperation(Account account, OCFile file) {
60 if (account == null)
61 throw new IllegalArgumentException("Illegal null account in DownloadFileOperation creation");
62 if (file == null)
63 throw new IllegalArgumentException("Illegal null file in DownloadFileOperation creation");
64
65 mAccount = account;
66 mFile = file;
67
68 }
69
70
71 public Account getAccount() {
72 return mAccount;
73 }
74
75 public OCFile getFile() {
76 return mFile;
77 }
78
79 public String getSavePath() {
80 String path = mFile.getStoragePath(); // re-downloads should be done over the original file
81 if (path != null && path.length() > 0) {
82 return path;
83 }
84 return FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile);
85 }
86
87 public String getTmpPath() {
88 return FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath();
89 }
90
91 public String getTmpFolder() {
92 return FileStorageUtils.getTemporalPath(mAccount.name);
93 }
94
95 public String getRemotePath() {
96 return mFile.getRemotePath();
97 }
98
99 public String getMimeType() {
100 String mimeType = mFile.getMimetype();
101 if (mimeType == null || mimeType.length() <= 0) {
102 try {
103 mimeType = MimeTypeMap.getSingleton()
104 .getMimeTypeFromExtension(
105 mFile.getRemotePath().substring(mFile.getRemotePath().lastIndexOf('.') + 1));
106 } catch (IndexOutOfBoundsException e) {
107 Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + mFile.getRemotePath());
108 }
109 }
110 if (mimeType == null) {
111 mimeType = "application/octet-stream";
112 }
113 return mimeType;
114 }
115
116 public long getSize() {
117 return mFile.getFileLength();
118 }
119
120 public long getModificationTimestamp() {
121 return (mModificationTimestamp > 0) ? mModificationTimestamp : mFile.getModificationTimestamp();
122 }
123
124 @Override
125 protected RemoteOperationResult run(OwnCloudClient client) {
126 RemoteOperationResult result = null;
127 File newFile = null;
128 boolean moved = true;
129
130 /// download will be performed to a temporal file, then moved to the final location
131 File tmpFile = new File(getTmpPath());
132
133 String tmpFolder = getTmpFolder();
134
135 /// perform the download
136 synchronized(mCancellationRequested) {
137 if (mCancellationRequested.get()) {
138 return new RemoteOperationResult(new OperationCancelledException());
139 }
140 }
141
142 mDownloadOperation = new DownloadRemoteFileOperation(mFile.getRemotePath(), tmpFolder);
143 Iterator<OnDatatransferProgressListener> listener = mDataTransferListeners.iterator();
144 while (listener.hasNext()) {
145 mDownloadOperation.addDatatransferProgressListener(listener.next());
146 }
147 result = mDownloadOperation.execute(client);
148
149 if (result.isSuccess()) {
150 mModificationTimestamp = mDownloadOperation.getModificationTimestamp();
151 newFile = new File(getSavePath());
152 newFile.getParentFile().mkdirs();
153 moved = tmpFile.renameTo(newFile);
154 if (!moved)
155 result = new RemoteOperationResult(RemoteOperationResult.ResultCode.LOCAL_STORAGE_NOT_MOVED);
156 }
157 Log_OC.i(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " + result.getLogMessage());
158
159 return result;
160 }
161
162 public void cancel() {
163 mCancellationRequested.set(true); // atomic set; there is no need of synchronizing it
164 if (mDownloadOperation != null) {
165 mDownloadOperation.cancel();
166 }
167 }
168
169
170 public void addDatatransferProgressListener (OnDatatransferProgressListener listener) {
171 synchronized (mDataTransferListeners) {
172 mDataTransferListeners.add(listener);
173 }
174 }
175
176 public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
177 synchronized (mDataTransferListeners) {
178 mDataTransferListeners.remove(listener);
179 }
180 }
181 }