Ensure that FileDownloader and FileUploader events are not lost
[pub/Android/ownCloud.git] / src / com / owncloud / android / datamodel / FileDataStorageManager.java
1 /* ownCloud Android client application
2 * Copyright (C) 2012 Bartek Przybylski
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
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.datamodel;
20
21 import java.io.File;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Vector;
27
28 import com.owncloud.android.db.ProviderMeta;
29 import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
30 import com.owncloud.android.utils.FileStorageUtils;
31
32 import android.accounts.Account;
33 import android.content.ContentProviderClient;
34 import android.content.ContentProviderOperation;
35 import android.content.ContentProviderResult;
36 import android.content.ContentResolver;
37 import android.content.ContentValues;
38 import android.content.OperationApplicationException;
39 import android.database.Cursor;
40 import android.net.Uri;
41 import android.os.RemoteException;
42 import android.util.Log;
43
44 public class FileDataStorageManager implements DataStorageManager {
45
46 private ContentResolver mContentResolver;
47 private ContentProviderClient mContentProvider;
48 private Account mAccount;
49
50 private static String TAG = "FileDataStorageManager";
51
52 public FileDataStorageManager(Account account, ContentResolver cr) {
53 mContentProvider = null;
54 mContentResolver = cr;
55 mAccount = account;
56 }
57
58 public FileDataStorageManager(Account account, ContentProviderClient cp) {
59 mContentProvider = cp;
60 mContentResolver = null;
61 mAccount = account;
62 }
63
64 @Override
65 public OCFile getFileByPath(String path) {
66 Cursor c = getCursorForValue(ProviderTableMeta.FILE_PATH, path);
67 OCFile file = null;
68 if (c.moveToFirst()) {
69 file = createFileInstance(c);
70 }
71 c.close();
72 return file;
73 }
74
75 @Override
76 public OCFile getFileById(long id) {
77 Cursor c = getCursorForValue(ProviderTableMeta._ID, String.valueOf(id));
78 OCFile file = null;
79 if (c.moveToFirst()) {
80 file = createFileInstance(c);
81 }
82 c.close();
83 return file;
84 }
85
86 public OCFile getFileByLocalPath(String path) {
87 Cursor c = getCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path);
88 OCFile file = null;
89 if (c.moveToFirst()) {
90 file = createFileInstance(c);
91 }
92 c.close();
93 return file;
94 }
95
96 @Override
97 public boolean fileExists(long id) {
98 return fileExists(ProviderTableMeta._ID, String.valueOf(id));
99 }
100
101 @Override
102 public boolean fileExists(String path) {
103 return fileExists(ProviderTableMeta.FILE_PATH, path);
104 }
105
106 @Override
107 public boolean saveFile(OCFile file) {
108 boolean overriden = false;
109 ContentValues cv = new ContentValues();
110 cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
111 cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
112 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
113 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
114 cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
115 if (file.getParentId() != 0)
116 cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
117 cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
118 if (!file.isDirectory())
119 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
120 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
121 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
122 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
123 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
124
125 if (fileExists(file.getRemotePath())) {
126 OCFile oldFile = getFileByPath(file.getRemotePath());
127 file.setFileId(oldFile.getFileId());
128
129 overriden = true;
130 if (getContentResolver() != null) {
131 getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv,
132 ProviderTableMeta._ID + "=?",
133 new String[] { String.valueOf(file.getFileId()) });
134 } else {
135 try {
136 getContentProvider().update(ProviderTableMeta.CONTENT_URI,
137 cv, ProviderTableMeta._ID + "=?",
138 new String[] { String.valueOf(file.getFileId()) });
139 } catch (RemoteException e) {
140 Log.e(TAG,
141 "Fail to insert insert file to database "
142 + e.getMessage());
143 }
144 }
145 } else {
146 Uri result_uri = null;
147 if (getContentResolver() != null) {
148 result_uri = getContentResolver().insert(
149 ProviderTableMeta.CONTENT_URI_FILE, cv);
150 } else {
151 try {
152 result_uri = getContentProvider().insert(
153 ProviderTableMeta.CONTENT_URI_FILE, cv);
154 } catch (RemoteException e) {
155 Log.e(TAG,
156 "Fail to insert insert file to database "
157 + e.getMessage());
158 }
159 }
160 if (result_uri != null) {
161 long new_id = Long.parseLong(result_uri.getPathSegments()
162 .get(1));
163 file.setFileId(new_id);
164 }
165 }
166
167 if (file.isDirectory() && file.needsUpdatingWhileSaving())
168 for (OCFile f : getDirectoryContent(file))
169 saveFile(f);
170
171 return overriden;
172 }
173
174
175 @Override
176 public void saveFiles(List<OCFile> files) {
177
178 Iterator<OCFile> filesIt = files.iterator();
179 ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(files.size());
180 OCFile file = null;
181
182 // prepare operations to perform
183 while (filesIt.hasNext()) {
184 file = filesIt.next();
185 ContentValues cv = new ContentValues();
186 cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
187 cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
188 cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
189 cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimetype());
190 cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
191 if (file.getParentId() != 0)
192 cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
193 cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
194 if (!file.isDirectory())
195 cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
196 cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
197 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
198 cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
199 cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.keepInSync() ? 1 : 0);
200
201 if (fileExists(file.getRemotePath())) {
202 OCFile oldFile = getFileByPath(file.getRemotePath());
203 file.setFileId(oldFile.getFileId());
204 operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
205 withValues(cv).
206 withSelection( ProviderTableMeta._ID + "=?",
207 new String[] { String.valueOf(file.getFileId()) })
208 .build());
209
210 } else {
211 operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).withValues(cv).build());
212 }
213 }
214
215 // apply operations in batch
216 ContentProviderResult[] results = null;
217 try {
218 if (getContentResolver() != null) {
219 results = getContentResolver().applyBatch(ProviderMeta.AUTHORITY_FILES, operations);
220
221 } else {
222 results = getContentProvider().applyBatch(operations);
223 }
224
225 } catch (OperationApplicationException e) {
226 Log.e(TAG, "Fail to update/insert list of files to database " + e.getMessage());
227
228 } catch (RemoteException e) {
229 Log.e(TAG, "Fail to update/insert list of files to database " + e.getMessage());
230 }
231
232 // update new id in file objects for insertions
233 if (results != null) {
234 long newId;
235 for (int i=0; i<results.length; i++) {
236 if (results[i].uri != null) {
237 newId = Long.parseLong(results[i].uri.getPathSegments().get(1));
238 files.get(i).setFileId(newId);
239 //Log.v(TAG, "Found and added id in insertion for " + files.get(i).getRemotePath());
240 }
241 }
242 }
243
244 for (OCFile aFile : files) {
245 if (aFile.isDirectory() && aFile.needsUpdatingWhileSaving())
246 saveFiles(getDirectoryContent(aFile));
247 }
248
249 }
250
251 public void setAccount(Account account) {
252 mAccount = account;
253 }
254
255 public Account getAccount() {
256 return mAccount;
257 }
258
259 public void setContentResolver(ContentResolver cr) {
260 mContentResolver = cr;
261 }
262
263 public ContentResolver getContentResolver() {
264 return mContentResolver;
265 }
266
267 public void setContentProvider(ContentProviderClient cp) {
268 mContentProvider = cp;
269 }
270
271 public ContentProviderClient getContentProvider() {
272 return mContentProvider;
273 }
274
275 @Override
276 public Vector<OCFile> getDirectoryContent(OCFile f) {
277 if (f != null && f.isDirectory() && f.getFileId() != -1) {
278 Vector<OCFile> ret = new Vector<OCFile>();
279
280 Uri req_uri = Uri.withAppendedPath(
281 ProviderTableMeta.CONTENT_URI_DIR,
282 String.valueOf(f.getFileId()));
283 Cursor c = null;
284
285 if (getContentProvider() != null) {
286 try {
287 c = getContentProvider().query(req_uri, null,
288 ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
289 new String[] { mAccount.name }, null);
290 } catch (RemoteException e) {
291 Log.e(TAG, e.getMessage());
292 return ret;
293 }
294 } else {
295 c = getContentResolver().query(req_uri, null,
296 ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
297 new String[] { mAccount.name }, null);
298 }
299
300 if (c.moveToFirst()) {
301 do {
302 OCFile child = createFileInstance(c);
303 ret.add(child);
304 } while (c.moveToNext());
305 }
306
307 c.close();
308
309 Collections.sort(ret);
310
311 return ret;
312 }
313 return null;
314 }
315
316 private boolean fileExists(String cmp_key, String value) {
317 Cursor c;
318 if (getContentResolver() != null) {
319 c = getContentResolver()
320 .query(ProviderTableMeta.CONTENT_URI,
321 null,
322 cmp_key + "=? AND "
323 + ProviderTableMeta.FILE_ACCOUNT_OWNER
324 + "=?",
325 new String[] { value, mAccount.name }, null);
326 } else {
327 try {
328 c = getContentProvider().query(
329 ProviderTableMeta.CONTENT_URI,
330 null,
331 cmp_key + "=? AND "
332 + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
333 new String[] { value, mAccount.name }, null);
334 } catch (RemoteException e) {
335 Log.e(TAG,
336 "Couldn't determine file existance, assuming non existance: "
337 + e.getMessage());
338 return false;
339 }
340 }
341 boolean retval = c.moveToFirst();
342 c.close();
343 return retval;
344 }
345
346 private Cursor getCursorForValue(String key, String value) {
347 Cursor c = null;
348 if (getContentResolver() != null) {
349 c = getContentResolver()
350 .query(ProviderTableMeta.CONTENT_URI,
351 null,
352 key + "=? AND "
353 + ProviderTableMeta.FILE_ACCOUNT_OWNER
354 + "=?",
355 new String[] { value, mAccount.name }, null);
356 } else {
357 try {
358 c = getContentProvider().query(
359 ProviderTableMeta.CONTENT_URI,
360 null,
361 key + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER
362 + "=?", new String[] { value, mAccount.name },
363 null);
364 } catch (RemoteException e) {
365 Log.e(TAG, "Could not get file details: " + e.getMessage());
366 c = null;
367 }
368 }
369 return c;
370 }
371
372 private OCFile createFileInstance(Cursor c) {
373 OCFile file = null;
374 if (c != null) {
375 file = new OCFile(c.getString(c
376 .getColumnIndex(ProviderTableMeta.FILE_PATH)));
377 file.setFileId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID)));
378 file.setParentId(c.getLong(c
379 .getColumnIndex(ProviderTableMeta.FILE_PARENT)));
380 file.setMimetype(c.getString(c
381 .getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)));
382 if (!file.isDirectory()) {
383 file.setStoragePath(c.getString(c
384 .getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH)));
385 if (file.getStoragePath() == null) {
386 // try to find existing file and bind it with current account; - with the current update of SynchronizeFolderOperation, this won't be necessary anymore after a full synchronization of the account
387 File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file));
388 if (f.exists()) {
389 file.setStoragePath(f.getAbsolutePath());
390 file.setLastSyncDateForData(f.lastModified());
391 }
392 }
393 }
394 file.setFileLength(c.getLong(c
395 .getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH)));
396 file.setCreationTimestamp(c.getLong(c
397 .getColumnIndex(ProviderTableMeta.FILE_CREATION)));
398 file.setModificationTimestamp(c.getLong(c
399 .getColumnIndex(ProviderTableMeta.FILE_MODIFIED)));
400 file.setLastSyncDateForProperties(c.getLong(c
401 .getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE)));
402 file.setLastSyncDateForData(c.getLong(c.
403 getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA)));
404 file.setKeepInSync(c.getInt(
405 c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false);
406 }
407 return file;
408 }
409
410 @Override
411 public void removeFile(OCFile file, boolean removeLocalCopy) {
412 Uri file_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, ""+file.getFileId());
413 if (getContentProvider() != null) {
414 try {
415 getContentProvider().delete(file_uri,
416 ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?",
417 new String[]{mAccount.name});
418 } catch (RemoteException e) {
419 e.printStackTrace();
420 }
421 } else {
422 getContentResolver().delete(file_uri,
423 ProviderTableMeta.FILE_ACCOUNT_OWNER+"=?",
424 new String[]{mAccount.name});
425 }
426 if (file.isDown() && removeLocalCopy) {
427 new File(file.getStoragePath()).delete();
428 }
429 }
430
431 }