Merge remote-tracking branch 'remotes/upstream/master' into beta
[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 String mEtag = "";
55 private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
56
57 private DownloadRemoteFileOperation mDownloadOperation;
58
59
60 public DownloadFileOperation(Account account, OCFile file) {
61 if (account == null)
62 throw new IllegalArgumentException("Illegal null account in DownloadFileOperation " +
63 "creation");
64 if (file == null)
65 throw new IllegalArgumentException("Illegal null file in DownloadFileOperation " +
66 "creation");
67
68 mAccount = account;
69 mFile = file;
70
71 }
72
73
74 public Account getAccount() {
75 return mAccount;
76 }
77
78 public OCFile getFile() {
79 return mFile;
80 }
81
82 public String getSavePath() {
83 String path = mFile.getStoragePath(); // re-downloads should be done over the original file
84 if (path != null && path.length() > 0) {
85 return path;
86 }
87 return FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile);
88 }
89
90 public String getTmpPath() {
91 return FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath();
92 }
93
94 public String getTmpFolder() {
95 return FileStorageUtils.getTemporalPath(mAccount.name);
96 }
97
98 public String getRemotePath() {
99 return mFile.getRemotePath();
100 }
101
102 public String getMimeType() {
103 String mimeType = mFile.getMimetype();
104 if (mimeType == null || mimeType.length() <= 0) {
105 try {
106 mimeType = MimeTypeMap.getSingleton()
107 .getMimeTypeFromExtension(
108 mFile.getRemotePath().substring(
109 mFile.getRemotePath().lastIndexOf('.') + 1));
110 } catch (IndexOutOfBoundsException e) {
111 Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " +
112 mFile.getRemotePath());
113 }
114 }
115 if (mimeType == null) {
116 mimeType = "application/octet-stream";
117 }
118 return mimeType;
119 }
120
121 public long getSize() {
122 return mFile.getFileLength();
123 }
124
125 public long getModificationTimestamp() {
126 return (mModificationTimestamp > 0) ? mModificationTimestamp :
127 mFile.getModificationTimestamp();
128 }
129
130 public String getEtag() {
131 return mEtag;
132 }
133
134 @Override
135 protected RemoteOperationResult run(OwnCloudClient client) {
136 RemoteOperationResult result;
137 File newFile;
138 boolean moved;
139
140 /// download will be performed to a temporal file, then moved to the final location
141 File tmpFile = new File(getTmpPath());
142
143 String tmpFolder = getTmpFolder();
144
145 /// perform the download
146 synchronized(mCancellationRequested) {
147 if (mCancellationRequested.get()) {
148 return new RemoteOperationResult(new OperationCancelledException());
149 }
150 }
151
152 mDownloadOperation = new DownloadRemoteFileOperation(mFile.getRemotePath(), tmpFolder);
153 Iterator<OnDatatransferProgressListener> listener = mDataTransferListeners.iterator();
154 while (listener.hasNext()) {
155 mDownloadOperation.addDatatransferProgressListener(listener.next());
156 }
157 result = mDownloadOperation.execute(client);
158
159 if (result.isSuccess()) {
160 mModificationTimestamp = mDownloadOperation.getModificationTimestamp();
161 mEtag = mDownloadOperation.getEtag();
162 newFile = new File(getSavePath());
163 newFile.getParentFile().mkdirs();
164 moved = tmpFile.renameTo(newFile);
165 if (!moved)
166 result = new RemoteOperationResult(
167 RemoteOperationResult.ResultCode.LOCAL_STORAGE_NOT_MOVED);
168 }
169 Log_OC.i(TAG, "Download of " + mFile.getRemotePath() + " to " + getSavePath() + ": " +
170 result.getLogMessage());
171
172 return result;
173 }
174
175 public void cancel() {
176 mCancellationRequested.set(true); // atomic set; there is no need of synchronizing it
177 if (mDownloadOperation != null) {
178 mDownloadOperation.cancel();
179 }
180 }
181
182
183 public void addDatatransferProgressListener (OnDatatransferProgressListener listener) {
184 synchronized (mDataTransferListeners) {
185 mDataTransferListeners.add(listener);
186 }
187 }
188
189 public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
190 synchronized (mDataTransferListeners) {
191 mDataTransferListeners.remove(listener);
192 }
193 }
194 }