Merge pull request #367 from LukeOwncloud/renamed_oc_framework_to_android_library
[pub/Android/ownCloud.git] / src / com / owncloud / android / operations / SynchronizeFileOperation.java
1 /* ownCloud Android client application
2 * Copyright (C) 2012 Bartek Przybylski
3 * Copyright (C) 2012-2013 ownCloud Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2,
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 package com.owncloud.android.operations;
20
21 import com.owncloud.android.datamodel.FileDataStorageManager;
22 import com.owncloud.android.datamodel.OCFile;
23 import com.owncloud.android.files.services.FileDownloader;
24 import com.owncloud.android.files.services.FileUploader;
25 import com.owncloud.android.lib.network.OwnCloudClient;
26 import com.owncloud.android.lib.operations.common.RemoteFile;
27 import com.owncloud.android.lib.operations.common.RemoteOperation;
28 import com.owncloud.android.lib.operations.common.RemoteOperationResult;
29 import com.owncloud.android.lib.operations.common.RemoteOperationResult.ResultCode;
30 import com.owncloud.android.lib.operations.remote.ReadRemoteFileOperation;
31 import com.owncloud.android.utils.FileStorageUtils;
32 import com.owncloud.android.utils.Log_OC;
33
34 import android.accounts.Account;
35 import android.content.Context;
36 import android.content.Intent;
37
38 /**
39 * Remote operation performing the read of remote file in the ownCloud server.
40 *
41 * @author David A. Velasco
42 * @author masensio
43 */
44
45 public class SynchronizeFileOperation extends RemoteOperation {
46
47 private String TAG = SynchronizeFileOperation.class.getSimpleName();
48
49 private OCFile mLocalFile;
50 private OCFile mServerFile;
51 private FileDataStorageManager mStorageManager;
52 private Account mAccount;
53 private boolean mSyncFileContents;
54 private Context mContext;
55
56 private boolean mTransferWasRequested = false;
57
58 public SynchronizeFileOperation(
59 OCFile localFile,
60 OCFile serverFile, // make this null to let the operation checks the server; added to reuse info from SynchronizeFolderOperation
61 FileDataStorageManager storageManager,
62 Account account,
63 boolean syncFileContents,
64 Context context) {
65
66 mLocalFile = localFile;
67 mServerFile = serverFile;
68 mStorageManager = storageManager;
69 mAccount = account;
70 mSyncFileContents = syncFileContents;
71 mContext = context;
72 }
73
74
75 @Override
76 protected RemoteOperationResult run(OwnCloudClient client) {
77
78 RemoteOperationResult result = null;
79 mTransferWasRequested = false;
80 if (!mLocalFile.isDown()) {
81 /// easy decision
82 requestForDownload(mLocalFile);
83 result = new RemoteOperationResult(ResultCode.OK);
84
85 } else {
86 /// local copy in the device -> need to think a bit more before do anything
87
88 if (mServerFile == null) {
89 String remotePath = mLocalFile.getRemotePath();
90 ReadRemoteFileOperation operation = new ReadRemoteFileOperation(remotePath);
91 result = operation.execute(client);
92 if (result.isSuccess()){
93 mServerFile = FileStorageUtils.fillOCFile((RemoteFile) result.getData().get(0));
94 mServerFile.setLastSyncDateForProperties(System.currentTimeMillis());
95 }
96 }
97
98 if (mServerFile != null) {
99
100 /// check changes in server and local file
101 boolean serverChanged = false;
102 /* time for eTag is coming, but not yet
103 if (mServerFile.getEtag() != null) {
104 serverChanged = (!mServerFile.getEtag().equals(mLocalFile.getEtag())); // TODO could this be dangerous when the user upgrades the server from non-tagged to tagged?
105 } else { */
106 // server without etags
107 serverChanged = (mServerFile.getModificationTimestamp() != mLocalFile.getModificationTimestampAtLastSyncForData());
108 //}
109 boolean localChanged = (mLocalFile.getLocalModificationTimestamp() > mLocalFile.getLastSyncDateForData());
110 // TODO this will be always true after the app is upgraded to database version 2; will result in unnecessary uploads
111
112 /// decide action to perform depending upon changes
113 //if (!mLocalFile.getEtag().isEmpty() && localChanged && serverChanged) {
114 if (localChanged && serverChanged) {
115 result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
116
117 } else if (localChanged) {
118 if (mSyncFileContents) {
119 requestForUpload(mLocalFile);
120 // the local update of file properties will be done by the FileUploader service when the upload finishes
121 } else {
122 // NOTHING TO DO HERE: updating the properties of the file in the server without uploading the contents would be stupid;
123 // So, an instance of SynchronizeFileOperation created with syncFileContents == false is completely useless when we suspect
124 // that an upload is necessary (for instance, in FileObserverService).
125 }
126 result = new RemoteOperationResult(ResultCode.OK);
127
128 } else if (serverChanged) {
129 if (mSyncFileContents) {
130 requestForDownload(mLocalFile); // local, not server; we won't to keep the value of keepInSync!
131 // the update of local data will be done later by the FileUploader service when the upload finishes
132 } else {
133 // TODO CHECK: is this really useful in some point in the code?
134 mServerFile.setKeepInSync(mLocalFile.keepInSync());
135 mServerFile.setLastSyncDateForData(mLocalFile.getLastSyncDateForData());
136 mServerFile.setStoragePath(mLocalFile.getStoragePath());
137 mServerFile.setParentId(mLocalFile.getParentId());
138 mStorageManager.saveFile(mServerFile);
139
140 }
141 result = new RemoteOperationResult(ResultCode.OK);
142
143 } else {
144 // nothing changed, nothing to do
145 result = new RemoteOperationResult(ResultCode.OK);
146 }
147
148 }
149
150 }
151
152 Log_OC.i(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() + ": " + result.getLogMessage());
153
154 return result;
155 }
156
157
158 /**
159 * Requests for an upload to the FileUploader service
160 *
161 * @param file OCFile object representing the file to upload
162 */
163 private void requestForUpload(OCFile file) {
164 Intent i = new Intent(mContext, FileUploader.class);
165 i.putExtra(FileUploader.KEY_ACCOUNT, mAccount);
166 i.putExtra(FileUploader.KEY_FILE, file);
167 /*i.putExtra(FileUploader.KEY_REMOTE_FILE, mRemotePath); // doing this we would lose the value of keepInSync in the road, and maybe it's not updated in the database when the FileUploader service gets it!
168 i.putExtra(FileUploader.KEY_LOCAL_FILE, localFile.getStoragePath());*/
169 i.putExtra(FileUploader.KEY_UPLOAD_TYPE, FileUploader.UPLOAD_SINGLE_FILE);
170 i.putExtra(FileUploader.KEY_FORCE_OVERWRITE, true);
171 mContext.startService(i);
172 mTransferWasRequested = true;
173 }
174
175
176 /**
177 * Requests for a download to the FileDownloader service
178 *
179 * @param file OCFile object representing the file to download
180 */
181 private void requestForDownload(OCFile file) {
182 Intent i = new Intent(mContext, FileDownloader.class);
183 i.putExtra(FileDownloader.EXTRA_ACCOUNT, mAccount);
184 i.putExtra(FileDownloader.EXTRA_FILE, file);
185 mContext.startService(i);
186 mTransferWasRequested = true;
187 }
188
189
190 public boolean transferWasRequested() {
191 return mTransferWasRequested;
192 }
193
194
195 public OCFile getLocalFile() {
196 return mLocalFile;
197 }
198
199 }