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