1 /* ownCloud Android client application
2 * Copyright (C) 2012 Bartek Przybylski
3 * Copyright (C) 2012-2013 ownCloud Inc.
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.
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.
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/>.
19 package com
.owncloud
.android
.operations
;
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
.RemoteOperation
;
27 import com
.owncloud
.android
.lib
.operations
.common
.RemoteOperationResult
;
28 import com
.owncloud
.android
.lib
.operations
.common
.RemoteOperationResult
.ResultCode
;
29 import com
.owncloud
.android
.lib
.operations
.remote
.ReadRemoteFileOperation
;
30 import com
.owncloud
.android
.utils
.FileStorageUtils
;
31 import com
.owncloud
.android
.utils
.Log_OC
;
33 import android
.accounts
.Account
;
34 import android
.content
.Context
;
35 import android
.content
.Intent
;
38 * Remote operation performing the read of remote file in the ownCloud server.
40 * @author David A. Velasco
44 public class SynchronizeFileOperation
extends RemoteOperation
{
46 private String TAG
= SynchronizeFileOperation
.class.getSimpleName();
48 private OCFile mLocalFile
;
49 private OCFile mServerFile
;
50 private FileDataStorageManager mStorageManager
;
51 private Account mAccount
;
52 private boolean mSyncFileContents
;
53 private Context mContext
;
55 private boolean mTransferWasRequested
= false
;
57 public SynchronizeFileOperation(
59 OCFile serverFile
, // make this null to let the operation checks the server; added to reuse info from SynchronizeFolderOperation
60 FileDataStorageManager storageManager
,
62 boolean syncFileContents
,
65 mLocalFile
= localFile
;
66 mServerFile
= serverFile
;
67 mStorageManager
= storageManager
;
69 mSyncFileContents
= syncFileContents
;
75 protected RemoteOperationResult
run(OwnCloudClient client
) {
77 RemoteOperationResult result
= null
;
78 mTransferWasRequested
= false
;
79 if (!mLocalFile
.isDown()) {
81 requestForDownload(mLocalFile
);
82 result
= new RemoteOperationResult(ResultCode
.OK
);
85 /// local copy in the device -> need to think a bit more before do anything
87 if (mServerFile
== null
) {
88 String remotePath
= mLocalFile
.getRemotePath();
89 ReadRemoteFileOperation operation
= new ReadRemoteFileOperation(remotePath
);
90 result
= operation
.execute(client
);
91 if (result
.isSuccess()){
92 mServerFile
= FileStorageUtils
.fillOCFile(result
.getData().get(0));
93 mServerFile
.setLastSyncDateForProperties(System
.currentTimeMillis());
97 if (result
.isSuccess()) {
99 /// check changes in server and local file
100 boolean serverChanged
= false
;
101 /* time for eTag is coming, but not yet
102 if (mServerFile.getEtag() != null) {
103 serverChanged = (!mServerFile.getEtag().equals(mLocalFile.getEtag())); // TODO could this be dangerous when the user upgrades the server from non-tagged to tagged?
105 // server without etags
106 serverChanged
= (mServerFile
.getModificationTimestamp() != mLocalFile
.getModificationTimestampAtLastSyncForData());
108 boolean localChanged
= (mLocalFile
.getLocalModificationTimestamp() > mLocalFile
.getLastSyncDateForData());
109 // TODO this will be always true after the app is upgraded to database version 2; will result in unnecessary uploads
111 /// decide action to perform depending upon changes
112 //if (!mLocalFile.getEtag().isEmpty() && localChanged && serverChanged) {
113 if (localChanged
&& serverChanged
) {
114 result
= new RemoteOperationResult(ResultCode
.SYNC_CONFLICT
);
116 } else if (localChanged
) {
117 if (mSyncFileContents
) {
118 requestForUpload(mLocalFile
);
119 // the local update of file properties will be done by the FileUploader service when the upload finishes
121 // NOTHING TO DO HERE: updating the properties of the file in the server without uploading the contents would be stupid;
122 // So, an instance of SynchronizeFileOperation created with syncFileContents == false is completely useless when we suspect
123 // that an upload is necessary (for instance, in FileObserverService).
125 result
= new RemoteOperationResult(ResultCode
.OK
);
127 } else if (serverChanged
) {
128 if (mSyncFileContents
) {
129 requestForDownload(mLocalFile
); // local, not server; we won't to keep the value of keepInSync!
130 // the update of local data will be done later by the FileUploader service when the upload finishes
132 // TODO CHECK: is this really useful in some point in the code?
133 mServerFile
.setKeepInSync(mLocalFile
.keepInSync());
134 mServerFile
.setLastSyncDateForData(mLocalFile
.getLastSyncDateForData());
135 mServerFile
.setStoragePath(mLocalFile
.getStoragePath());
136 mServerFile
.setParentId(mLocalFile
.getParentId());
137 mStorageManager
.saveFile(mServerFile
);
140 result
= new RemoteOperationResult(ResultCode
.OK
);
143 // nothing changed, nothing to do
144 result
= new RemoteOperationResult(ResultCode
.OK
);
151 Log_OC
.i(TAG
, "Synchronizing " + mAccount
.name
+ ", file " + mLocalFile
.getRemotePath() + ": " + result
.getLogMessage());
158 * Requests for an upload to the FileUploader service
160 * @param file OCFile object representing the file to upload
162 private void requestForUpload(OCFile file
) {
163 Intent i
= new Intent(mContext
, FileUploader
.class);
164 i
.putExtra(FileUploader
.KEY_ACCOUNT
, mAccount
);
165 i
.putExtra(FileUploader
.KEY_FILE
, file
);
166 /*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!
167 i.putExtra(FileUploader.KEY_LOCAL_FILE, localFile.getStoragePath());*/
168 i
.putExtra(FileUploader
.KEY_UPLOAD_TYPE
, FileUploader
.UPLOAD_SINGLE_FILE
);
169 i
.putExtra(FileUploader
.KEY_FORCE_OVERWRITE
, true
);
170 mContext
.startService(i
);
171 mTransferWasRequested
= true
;
176 * Requests for a download to the FileDownloader service
178 * @param file OCFile object representing the file to download
180 private void requestForDownload(OCFile file
) {
181 Intent i
= new Intent(mContext
, FileDownloader
.class);
182 i
.putExtra(FileDownloader
.EXTRA_ACCOUNT
, mAccount
);
183 i
.putExtra(FileDownloader
.EXTRA_FILE
, file
);
184 mContext
.startService(i
);
185 mTransferWasRequested
= true
;
189 public boolean transferWasRequested() {
190 return mTransferWasRequested
;
194 public OCFile
getLocalFile() {