1 /* ownCloud Android client application
2 * Copyright (C) 2012 Bartek Przybylski
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.
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
.datamodel
;
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
;
28 import com
.owncloud
.android
.db
.ProviderMeta
;
29 import com
.owncloud
.android
.db
.ProviderMeta
.ProviderTableMeta
;
30 import com
.owncloud
.android
.utils
.FileStorageUtils
;
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
;
44 public class FileDataStorageManager
implements DataStorageManager
{
46 private ContentResolver mContentResolver
;
47 private ContentProviderClient mContentProvider
;
48 private Account mAccount
;
50 private static String TAG
= "FileDataStorageManager";
52 public FileDataStorageManager(Account account
, ContentResolver cr
) {
53 mContentProvider
= null
;
54 mContentResolver
= cr
;
58 public FileDataStorageManager(Account account
, ContentProviderClient cp
) {
59 mContentProvider
= cp
;
60 mContentResolver
= null
;
65 public OCFile
getFileByPath(String path
) {
66 Cursor c
= getCursorForValue(ProviderTableMeta
.FILE_PATH
, path
);
68 if (c
.moveToFirst()) {
69 file
= createFileInstance(c
);
76 public OCFile
getFileById(long id
) {
77 Cursor c
= getCursorForValue(ProviderTableMeta
._ID
, String
.valueOf(id
));
79 if (c
.moveToFirst()) {
80 file
= createFileInstance(c
);
86 public OCFile
getFileByLocalPath(String path
) {
87 Cursor c
= getCursorForValue(ProviderTableMeta
.FILE_STORAGE_PATH
, path
);
89 if (c
.moveToFirst()) {
90 file
= createFileInstance(c
);
97 public boolean fileExists(long id
) {
98 return fileExists(ProviderTableMeta
._ID
, String
.valueOf(id
));
102 public boolean fileExists(String path
) {
103 return fileExists(ProviderTableMeta
.FILE_PATH
, path
);
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);
125 if (fileExists(file
.getRemotePath())) {
126 OCFile oldFile
= getFileByPath(file
.getRemotePath());
127 file
.setFileId(oldFile
.getFileId());
130 if (getContentResolver() != null
) {
131 getContentResolver().update(ProviderTableMeta
.CONTENT_URI
, cv
,
132 ProviderTableMeta
._ID
+ "=?",
133 new String
[] { String
.valueOf(file
.getFileId()) });
136 getContentProvider().update(ProviderTableMeta
.CONTENT_URI
,
137 cv
, ProviderTableMeta
._ID
+ "=?",
138 new String
[] { String
.valueOf(file
.getFileId()) });
139 } catch (RemoteException e
) {
141 "Fail to insert insert file to database "
146 Uri result_uri
= null
;
147 if (getContentResolver() != null
) {
148 result_uri
= getContentResolver().insert(
149 ProviderTableMeta
.CONTENT_URI_FILE
, cv
);
152 result_uri
= getContentProvider().insert(
153 ProviderTableMeta
.CONTENT_URI_FILE
, cv
);
154 } catch (RemoteException e
) {
156 "Fail to insert insert file to database "
160 if (result_uri
!= null
) {
161 long new_id
= Long
.parseLong(result_uri
.getPathSegments()
163 file
.setFileId(new_id
);
167 if (file
.isDirectory() && file
.needsUpdatingWhileSaving())
168 for (OCFile f
: getDirectoryContent(file
))
176 public void saveFiles(List
<OCFile
> files
) {
178 Iterator
<OCFile
> filesIt
= files
.iterator();
179 ArrayList
<ContentProviderOperation
> operations
= new ArrayList
<ContentProviderOperation
>(files
.size());
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);
201 if (fileExists(file
.getRemotePath())) {
202 OCFile oldFile
= getFileByPath(file
.getRemotePath());
203 file
.setFileId(oldFile
.getFileId());
204 operations
.add(ContentProviderOperation
.newUpdate(ProviderTableMeta
.CONTENT_URI
).
206 withSelection( ProviderTableMeta
._ID
+ "=?",
207 new String
[] { String
.valueOf(file
.getFileId()) })
211 operations
.add(ContentProviderOperation
.newInsert(ProviderTableMeta
.CONTENT_URI
).withValues(cv
).build());
215 // apply operations in batch
216 ContentProviderResult
[] results
= null
;
218 if (getContentResolver() != null
) {
219 results
= getContentResolver().applyBatch(ProviderMeta
.AUTHORITY_FILES
, operations
);
222 results
= getContentProvider().applyBatch(operations
);
225 } catch (OperationApplicationException e
) {
226 Log
.e(TAG
, "Fail to update/insert list of files to database " + e
.getMessage());
228 } catch (RemoteException e
) {
229 Log
.e(TAG
, "Fail to update/insert list of files to database " + e
.getMessage());
232 // update new id in file objects for insertions
233 if (results
!= null
) {
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());
244 for (OCFile aFile
: files
) {
245 if (aFile
.isDirectory() && aFile
.needsUpdatingWhileSaving())
246 saveFiles(getDirectoryContent(aFile
));
251 public void setAccount(Account account
) {
255 public Account
getAccount() {
259 public void setContentResolver(ContentResolver cr
) {
260 mContentResolver
= cr
;
263 public ContentResolver
getContentResolver() {
264 return mContentResolver
;
267 public void setContentProvider(ContentProviderClient cp
) {
268 mContentProvider
= cp
;
271 public ContentProviderClient
getContentProvider() {
272 return mContentProvider
;
276 public Vector
<OCFile
> getDirectoryContent(OCFile f
) {
277 if (f
!= null
&& f
.isDirectory() && f
.getFileId() != -1) {
278 Vector
<OCFile
> ret
= new Vector
<OCFile
>();
280 Uri req_uri
= Uri
.withAppendedPath(
281 ProviderTableMeta
.CONTENT_URI_DIR
,
282 String
.valueOf(f
.getFileId()));
285 if (getContentProvider() != null
) {
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());
295 c
= getContentResolver().query(req_uri
, null
,
296 ProviderTableMeta
.FILE_ACCOUNT_OWNER
+ "=?",
297 new String
[] { mAccount
.name
}, null
);
300 if (c
.moveToFirst()) {
302 OCFile child
= createFileInstance(c
);
304 } while (c
.moveToNext());
309 Collections
.sort(ret
);
316 private boolean fileExists(String cmp_key
, String value
) {
318 if (getContentResolver() != null
) {
319 c
= getContentResolver()
320 .query(ProviderTableMeta
.CONTENT_URI
,
323 + ProviderTableMeta
.FILE_ACCOUNT_OWNER
325 new String
[] { value
, mAccount
.name
}, null
);
328 c
= getContentProvider().query(
329 ProviderTableMeta
.CONTENT_URI
,
332 + ProviderTableMeta
.FILE_ACCOUNT_OWNER
+ "=?",
333 new String
[] { value
, mAccount
.name
}, null
);
334 } catch (RemoteException e
) {
336 "Couldn't determine file existance, assuming non existance: "
341 boolean retval
= c
.moveToFirst();
346 private Cursor
getCursorForValue(String key
, String value
) {
348 if (getContentResolver() != null
) {
349 c
= getContentResolver()
350 .query(ProviderTableMeta
.CONTENT_URI
,
353 + ProviderTableMeta
.FILE_ACCOUNT_OWNER
355 new String
[] { value
, mAccount
.name
}, null
);
358 c
= getContentProvider().query(
359 ProviderTableMeta
.CONTENT_URI
,
361 key
+ "=? AND " + ProviderTableMeta
.FILE_ACCOUNT_OWNER
362 + "=?", new String
[] { value
, mAccount
.name
},
364 } catch (RemoteException e
) {
365 Log
.e(TAG
, "Could not get file details: " + e
.getMessage());
372 private OCFile
createFileInstance(Cursor c
) {
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
));
389 file
.setStoragePath(f
.getAbsolutePath());
390 file
.setLastSyncDateForData(f
.lastModified());
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
);
411 public void removeFile(OCFile file
, boolean removeLocalCopy
) {
412 Uri file_uri
= Uri
.withAppendedPath(ProviderTableMeta
.CONTENT_URI_FILE
, ""+file
.getFileId());
413 if (getContentProvider() != null
) {
415 getContentProvider().delete(file_uri
,
416 ProviderTableMeta
.FILE_ACCOUNT_OWNER
+"=?",
417 new String
[]{mAccount
.name
});
418 } catch (RemoteException e
) {
422 getContentResolver().delete(file_uri
,
423 ProviderTableMeta
.FILE_ACCOUNT_OWNER
+"=?",
424 new String
[]{mAccount
.name
});
426 if (file
.isDown() && removeLocalCopy
) {
427 new File(file
.getStoragePath()).delete();