FileDataStorageManager.java 107 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302
  1. /*
  2. * ownCloud Android client application
  3. *
  4. * Copyright (C) 2012 Bartek Przybylski
  5. * Copyright (C) 2015 ownCloud Inc.
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2,
  9. * as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. package com.owncloud.android.datamodel;
  20. import android.accounts.Account;
  21. import android.content.ContentProviderClient;
  22. import android.content.ContentProviderOperation;
  23. import android.content.ContentProviderResult;
  24. import android.content.ContentResolver;
  25. import android.content.ContentUris;
  26. import android.content.ContentValues;
  27. import android.content.Context;
  28. import android.content.Intent;
  29. import android.content.OperationApplicationException;
  30. import android.database.Cursor;
  31. import android.net.Uri;
  32. import android.os.RemoteException;
  33. import android.provider.MediaStore;
  34. import android.text.TextUtils;
  35. import com.google.gson.Gson;
  36. import com.google.gson.JsonSyntaxException;
  37. import com.owncloud.android.MainApp;
  38. import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
  39. import com.owncloud.android.lib.common.network.WebdavEntry;
  40. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  41. import com.owncloud.android.lib.common.utils.Log_OC;
  42. import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation;
  43. import com.owncloud.android.lib.resources.files.model.RemoteFile;
  44. import com.owncloud.android.lib.resources.shares.OCShare;
  45. import com.owncloud.android.lib.resources.shares.ShareType;
  46. import com.owncloud.android.lib.resources.shares.ShareeUser;
  47. import com.owncloud.android.lib.resources.status.CapabilityBooleanType;
  48. import com.owncloud.android.lib.resources.status.OCCapability;
  49. import com.owncloud.android.operations.RemoteOperationFailedException;
  50. import com.owncloud.android.utils.FileStorageUtils;
  51. import com.owncloud.android.utils.MimeType;
  52. import com.owncloud.android.utils.MimeTypeUtil;
  53. import org.jetbrains.annotations.NotNull;
  54. import java.io.File;
  55. import java.util.ArrayList;
  56. import java.util.Arrays;
  57. import java.util.Collection;
  58. import java.util.Collections;
  59. import java.util.HashSet;
  60. import java.util.Iterator;
  61. import java.util.List;
  62. import java.util.Locale;
  63. import java.util.Set;
  64. import androidx.annotation.NonNull;
  65. import androidx.annotation.Nullable;
  66. import lombok.Getter;
  67. import lombok.Setter;
  68. @Getter
  69. public class FileDataStorageManager {
  70. private static final String TAG = FileDataStorageManager.class.getSimpleName();
  71. private static final String AND = "=? AND ";
  72. private static final String FAILED_TO_INSERT_MSG = "Fail to insert insert file to database ";
  73. private static final String SENDING_TO_FILECONTENTPROVIDER_MSG = "Sending %d operations to FileContentProvider";
  74. private static final String EXCEPTION_MSG = "Exception in batch of operations ";
  75. public static final int ROOT_PARENT_ID = 0;
  76. public static final String NULL_STRING = "null";
  77. private ContentResolver contentResolver;
  78. private ContentProviderClient contentProviderClient;
  79. @Setter private Account account;
  80. public FileDataStorageManager(Account account, ContentResolver cr) {
  81. contentProviderClient = null;
  82. contentResolver = cr;
  83. this.account = account;
  84. }
  85. public FileDataStorageManager(Account account, ContentProviderClient cp) {
  86. contentProviderClient = cp;
  87. contentResolver = null;
  88. this.account = account;
  89. }
  90. public OCFile getFileByPath(String path) {
  91. Cursor c = getFileCursorForValue(ProviderTableMeta.FILE_PATH, path);
  92. OCFile file = null;
  93. if (c.moveToFirst()) {
  94. file = createFileInstance(c);
  95. }
  96. c.close();
  97. if (file == null && OCFile.ROOT_PATH.equals(path)) {
  98. return createRootDir(); // root should always exist
  99. }
  100. return file;
  101. }
  102. public @Nullable
  103. OCFile getFileById(long id) {
  104. Cursor c = getFileCursorForValue(ProviderTableMeta._ID, String.valueOf(id));
  105. OCFile file = null;
  106. if (c.moveToFirst()) {
  107. file = createFileInstance(c);
  108. }
  109. c.close();
  110. return file;
  111. }
  112. public OCFile getFileByLocalPath(String path) {
  113. Cursor c = getFileCursorForValue(ProviderTableMeta.FILE_STORAGE_PATH, path);
  114. OCFile file = null;
  115. if (c.moveToFirst()) {
  116. file = createFileInstance(c);
  117. }
  118. c.close();
  119. return file;
  120. }
  121. public @Nullable
  122. OCFile getFileByRemoteId(String remoteId) {
  123. Cursor c = getFileCursorForValue(ProviderTableMeta.FILE_REMOTE_ID, remoteId);
  124. OCFile file = null;
  125. if (c.moveToFirst()) {
  126. file = createFileInstance(c);
  127. }
  128. c.close();
  129. return file;
  130. }
  131. public boolean fileExists(long id) {
  132. return fileExists(ProviderTableMeta._ID, String.valueOf(id));
  133. }
  134. public boolean fileExists(String path) {
  135. return fileExists(ProviderTableMeta.FILE_PATH, path);
  136. }
  137. public List<OCFile> getFolderContent(OCFile f, boolean onlyOnDevice) {
  138. if (f != null && f.isFolder() && f.getFileId() != -1) {
  139. return getFolderContent(f.getFileId(), onlyOnDevice);
  140. } else {
  141. return new ArrayList<>();
  142. }
  143. }
  144. public List<OCFile> getFolderImages(OCFile folder, boolean onlyOnDevice) {
  145. List<OCFile> ret = new ArrayList<>();
  146. if (folder != null) {
  147. // TODO better implementation, filtering in the access to database instead of here
  148. List<OCFile> tmp = getFolderContent(folder, onlyOnDevice);
  149. for (OCFile file : tmp) {
  150. if (MimeTypeUtil.isImage(file)) {
  151. ret.add(file);
  152. }
  153. }
  154. }
  155. return ret;
  156. }
  157. public boolean saveFile(OCFile file) {
  158. boolean overridden = false;
  159. ContentValues cv = new ContentValues();
  160. cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
  161. cv.put(
  162. ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
  163. file.getModificationTimestampAtLastSyncForData()
  164. );
  165. cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
  166. cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
  167. cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimeType());
  168. cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
  169. cv.put(ProviderTableMeta.FILE_ENCRYPTED_NAME, file.getEncryptedFileName());
  170. cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
  171. cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
  172. if (!file.isFolder()) {
  173. cv.put(ProviderTableMeta.FILE_IS_ENCRYPTED, file.isEncrypted());
  174. cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
  175. }
  176. cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, account.name);
  177. cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
  178. cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
  179. cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
  180. cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, file.getEtagOnServer());
  181. cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0);
  182. cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0);
  183. cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
  184. cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
  185. cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
  186. cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.isUpdateThumbnailNeeded());
  187. cv.put(ProviderTableMeta.FILE_IS_DOWNLOADING, file.isDownloading());
  188. cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, file.getEtagInConflict());
  189. cv.put(ProviderTableMeta.FILE_UNREAD_COMMENTS_COUNT, file.getUnreadCommentsCount());
  190. cv.put(ProviderTableMeta.FILE_OWNER_ID, file.getOwnerId());
  191. cv.put(ProviderTableMeta.FILE_OWNER_DISPLAY_NAME, file.getOwnerDisplayName());
  192. cv.put(ProviderTableMeta.FILE_NOTE, file.getNote());
  193. cv.put(ProviderTableMeta.FILE_SHAREES, new Gson().toJson(file.getSharees()));
  194. boolean sameRemotePath = fileExists(file.getRemotePath());
  195. if (sameRemotePath ||
  196. fileExists(file.getFileId())) { // for renamed files; no more delete and create
  197. if (sameRemotePath) {
  198. OCFile oldFile = getFileByPath(file.getRemotePath());
  199. file.setFileId(oldFile.getFileId());
  200. }
  201. overridden = true;
  202. if (getContentResolver() != null) {
  203. getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv,
  204. ProviderTableMeta._ID + "=?",
  205. new String[]{String.valueOf(file.getFileId())});
  206. } else {
  207. try {
  208. getContentProviderClient().update(ProviderTableMeta.CONTENT_URI,
  209. cv, ProviderTableMeta._ID + "=?",
  210. new String[]{String.valueOf(file.getFileId())});
  211. } catch (RemoteException e) {
  212. Log_OC.e(TAG, FAILED_TO_INSERT_MSG + e.getMessage(), e);
  213. }
  214. }
  215. } else {
  216. Uri result_uri = null;
  217. if (getContentResolver() != null) {
  218. result_uri = getContentResolver().insert(ProviderTableMeta.CONTENT_URI_FILE, cv);
  219. } else {
  220. try {
  221. result_uri = getContentProviderClient().insert(ProviderTableMeta.CONTENT_URI_FILE, cv);
  222. } catch (RemoteException e) {
  223. Log_OC.e(TAG, FAILED_TO_INSERT_MSG + e.getMessage(), e);
  224. }
  225. }
  226. if (result_uri != null) {
  227. long new_id = Long.parseLong(result_uri.getPathSegments().get(1));
  228. file.setFileId(new_id);
  229. }
  230. }
  231. return overridden;
  232. }
  233. /**
  234. * traverses a files parent tree to be able to store a file with its parents.
  235. * Throws a RemoteOperationFailedException in case the parent can't be retrieved.
  236. *
  237. * @param file the file
  238. * @param context the app context
  239. * @return the parent file
  240. */
  241. public OCFile saveFileWithParent(OCFile file, Context context) {
  242. if (file.getParentId() == 0 && !OCFile.ROOT_PATH.equals(file.getRemotePath())) {
  243. String remotePath = file.getRemotePath();
  244. String parentPath = remotePath.substring(0, remotePath.lastIndexOf(file.getFileName()));
  245. OCFile parentFile = getFileByPath(parentPath);
  246. OCFile returnFile;
  247. if (parentFile == null) {
  248. // remote request
  249. ReadFileRemoteOperation operation = new ReadFileRemoteOperation(parentPath);
  250. RemoteOperationResult result = operation.execute(getAccount(), context);
  251. if (result.isSuccess()) {
  252. OCFile remoteFolder = FileStorageUtils.fillOCFile((RemoteFile) result.getData().get(0));
  253. returnFile = saveFileWithParent(remoteFolder, context);
  254. } else {
  255. Exception exception = result.getException();
  256. String message = "Error during saving file with parents: " + file.getRemotePath() + " / "
  257. + result.getLogMessage();
  258. if (exception != null) {
  259. throw new RemoteOperationFailedException(message, exception);
  260. } else {
  261. throw new RemoteOperationFailedException(message);
  262. }
  263. }
  264. } else {
  265. returnFile = saveFileWithParent(parentFile, context);
  266. }
  267. file.setParentId(returnFile.getFileId());
  268. saveFile(file);
  269. }
  270. return file;
  271. }
  272. public void saveNewFile(OCFile newFile) {
  273. String remoteParentPath = new File(newFile.getRemotePath()).getParent();
  274. remoteParentPath = remoteParentPath.endsWith(OCFile.PATH_SEPARATOR) ?
  275. remoteParentPath : remoteParentPath + OCFile.PATH_SEPARATOR;
  276. OCFile parent = getFileByPath(remoteParentPath);
  277. if (parent != null) {
  278. newFile.setParentId(parent.getFileId());
  279. saveFile(newFile);
  280. } else {
  281. throw new IllegalArgumentException("Saving a new file in an unexisting folder");
  282. }
  283. }
  284. /**
  285. * Inserts or updates the list of files contained in a given folder.
  286. *
  287. * CALLER IS RESPONSIBLE FOR GRANTING RIGHT UPDATE OF INFORMATION, NOT THIS METHOD.
  288. * HERE ONLY DATA CONSISTENCY SHOULD BE GRANTED
  289. *
  290. * @param folder
  291. * @param updatedFiles
  292. * @param filesToRemove
  293. */
  294. public void saveFolder(OCFile folder, Collection<OCFile> updatedFiles, Collection<OCFile> filesToRemove) {
  295. Log_OC.d(TAG, "Saving folder " + folder.getRemotePath() + " with " + updatedFiles.size()
  296. + " children and " + filesToRemove.size() + " files to remove");
  297. ArrayList<ContentProviderOperation> operations = new ArrayList<>(updatedFiles.size());
  298. // prepare operations to insert or update files to save in the given folder
  299. for (OCFile file : updatedFiles) {
  300. ContentValues cv = createContentValueForFile(file, folder);
  301. if (fileExists(file.getFileId()) || fileExists(file.getRemotePath())) {
  302. long fileId;
  303. if (file.getFileId() != -1) {
  304. fileId = file.getFileId();
  305. } else {
  306. fileId = getFileByPath(file.getRemotePath()).getFileId();
  307. }
  308. // updating an existing file
  309. operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI)
  310. .withValues(cv)
  311. .withSelection(ProviderTableMeta._ID + "=?", new String[]{String.valueOf(fileId)})
  312. .build());
  313. } else {
  314. // adding a new file
  315. operations.add(ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).withValues(cv).build());
  316. }
  317. }
  318. // prepare operations to remove files in the given folder
  319. String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + AND + ProviderTableMeta.FILE_PATH + "=?";
  320. String[] whereArgs = new String[2];
  321. for (OCFile file : filesToRemove) {
  322. if (file.getParentId() == folder.getFileId()) {
  323. whereArgs[0] = account.name;
  324. whereArgs[1] = file.getRemotePath();
  325. if (file.isFolder()) {
  326. operations.add(ContentProviderOperation.newDelete(
  327. ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_DIR, file.getFileId()))
  328. .withSelection(where, whereArgs).build());
  329. File localFolder = new File(FileStorageUtils.getDefaultSavePathFor(account.name, file));
  330. if (localFolder.exists()) {
  331. removeLocalFolder(localFolder);
  332. }
  333. } else {
  334. operations.add(ContentProviderOperation.newDelete(
  335. ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, file.getFileId()))
  336. .withSelection(where, whereArgs).build());
  337. if (file.isDown()) {
  338. String path = file.getStoragePath();
  339. if (new File(path).delete()) {
  340. triggerMediaScan(path); // notify MediaScanner about removed file
  341. }
  342. }
  343. }
  344. }
  345. }
  346. // update metadata of folder
  347. ContentValues cv = createContentValueForFile(folder);
  348. operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI)
  349. .withValues(cv)
  350. .withSelection(ProviderTableMeta._ID + "=?", new String[]{String.valueOf(folder.getFileId())})
  351. .build());
  352. // apply operations in batch
  353. ContentProviderResult[] results = null;
  354. Log_OC.d(TAG, String.format(Locale.ENGLISH, SENDING_TO_FILECONTENTPROVIDER_MSG, operations.size()));
  355. try {
  356. if (getContentResolver() != null) {
  357. results = getContentResolver().applyBatch(MainApp.getAuthority(), operations);
  358. } else {
  359. results = getContentProviderClient().applyBatch(operations);
  360. }
  361. } catch (OperationApplicationException | RemoteException e) {
  362. Log_OC.e(TAG, EXCEPTION_MSG + e.getMessage(), e);
  363. }
  364. // update new id in file objects for insertions
  365. if (results != null) {
  366. long newId;
  367. Iterator<OCFile> filesIt = updatedFiles.iterator();
  368. OCFile file;
  369. for (ContentProviderResult result : results) {
  370. if (filesIt.hasNext()) {
  371. file = filesIt.next();
  372. } else {
  373. file = null;
  374. }
  375. if (result.uri != null) {
  376. newId = Long.parseLong(result.uri.getPathSegments().get(1));
  377. //updatedFiles.get(i).setFileId(newId);
  378. if (file != null) {
  379. file.setFileId(newId);
  380. }
  381. }
  382. }
  383. }
  384. }
  385. private ContentValues createContentValueForFile(OCFile folder) {
  386. ContentValues cv = new ContentValues();
  387. cv.put(ProviderTableMeta.FILE_MODIFIED, folder.getModificationTimestamp());
  388. cv.put(
  389. ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
  390. folder.getModificationTimestampAtLastSyncForData()
  391. );
  392. cv.put(ProviderTableMeta.FILE_CREATION, folder.getCreationTimestamp());
  393. cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, 0);
  394. cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, folder.getMimeType());
  395. cv.put(ProviderTableMeta.FILE_NAME, folder.getFileName());
  396. cv.put(ProviderTableMeta.FILE_PARENT, folder.getParentId());
  397. cv.put(ProviderTableMeta.FILE_PATH, folder.getRemotePath());
  398. cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, account.name);
  399. cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, folder.getLastSyncDateForProperties());
  400. cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, folder.getLastSyncDateForData());
  401. cv.put(ProviderTableMeta.FILE_ETAG, folder.getEtag());
  402. cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, folder.getEtagOnServer());
  403. cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, folder.isSharedViaLink() ? 1 : 0);
  404. cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, folder.isSharedWithSharee() ? 1 : 0);
  405. cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, folder.getPublicLink());
  406. cv.put(ProviderTableMeta.FILE_PERMISSIONS, folder.getPermissions());
  407. cv.put(ProviderTableMeta.FILE_REMOTE_ID, folder.getRemoteId());
  408. cv.put(ProviderTableMeta.FILE_FAVORITE, folder.isFavorite());
  409. cv.put(ProviderTableMeta.FILE_IS_ENCRYPTED, folder.isEncrypted());
  410. cv.put(ProviderTableMeta.FILE_UNREAD_COMMENTS_COUNT, folder.getUnreadCommentsCount());
  411. cv.put(ProviderTableMeta.FILE_OWNER_ID, folder.getOwnerId());
  412. cv.put(ProviderTableMeta.FILE_OWNER_DISPLAY_NAME, folder.getOwnerDisplayName());
  413. cv.put(ProviderTableMeta.FILE_NOTE, folder.getNote());
  414. cv.put(ProviderTableMeta.FILE_SHAREES, new Gson().toJson(folder.getSharees()));
  415. return cv;
  416. }
  417. private ContentValues createContentValueForFile(OCFile file, OCFile folder) {
  418. ContentValues cv = new ContentValues();
  419. cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
  420. cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, file.getModificationTimestampAtLastSyncForData());
  421. cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
  422. cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
  423. cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimeType());
  424. cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
  425. cv.put(ProviderTableMeta.FILE_ENCRYPTED_NAME, file.getEncryptedFileName());
  426. cv.put(ProviderTableMeta.FILE_PARENT, folder.getFileId());
  427. cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
  428. if (!file.isFolder()) {
  429. cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
  430. }
  431. cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, account.name);
  432. cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
  433. cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
  434. cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
  435. cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, file.getEtagOnServer());
  436. cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0);
  437. cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0);
  438. cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
  439. cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
  440. cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
  441. cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.isUpdateThumbnailNeeded());
  442. cv.put(ProviderTableMeta.FILE_IS_DOWNLOADING, file.isDownloading());
  443. cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, file.getEtagInConflict());
  444. cv.put(ProviderTableMeta.FILE_FAVORITE, file.isFavorite());
  445. cv.put(ProviderTableMeta.FILE_IS_ENCRYPTED, file.isEncrypted());
  446. cv.put(ProviderTableMeta.FILE_MOUNT_TYPE, file.getMountType().ordinal());
  447. cv.put(ProviderTableMeta.FILE_HAS_PREVIEW, file.isPreviewAvailable() ? 1 : 0);
  448. cv.put(ProviderTableMeta.FILE_UNREAD_COMMENTS_COUNT, file.getUnreadCommentsCount());
  449. cv.put(ProviderTableMeta.FILE_OWNER_ID, file.getOwnerId());
  450. cv.put(ProviderTableMeta.FILE_OWNER_DISPLAY_NAME, file.getOwnerDisplayName());
  451. cv.put(ProviderTableMeta.FILE_NOTE, file.getNote());
  452. cv.put(ProviderTableMeta.FILE_SHAREES, new Gson().toJson(file.getSharees()));
  453. return cv;
  454. }
  455. public boolean removeFile(OCFile file, boolean removeDBData, boolean removeLocalCopy) {
  456. boolean success = true;
  457. if (file != null) {
  458. if (file.isFolder()) {
  459. success = removeFolder(file, removeDBData, removeLocalCopy);
  460. } else {
  461. if (removeDBData) {
  462. //Uri file_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE,
  463. // ""+file.getFileId());
  464. Uri file_uri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, file.getFileId());
  465. String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + AND + ProviderTableMeta.FILE_PATH + "=?";
  466. String[] whereArgs = new String[]{account.name, file.getRemotePath()};
  467. int deleted = 0;
  468. if (getContentProviderClient() != null) {
  469. try {
  470. deleted = getContentProviderClient().delete(file_uri, where, whereArgs);
  471. } catch (RemoteException e) {
  472. Log_OC.d(TAG, e.getMessage(), e);
  473. }
  474. } else {
  475. deleted = getContentResolver().delete(file_uri, where, whereArgs);
  476. }
  477. success = deleted > 0;
  478. }
  479. String localPath = file.getStoragePath();
  480. if (removeLocalCopy && file.isDown() && localPath != null && success) {
  481. success = new File(localPath).delete();
  482. if (success) {
  483. deleteFileInMediaScan(localPath);
  484. }
  485. if (!removeDBData && success) {
  486. // maybe unnecessary, but should be checked TODO remove if unnecessary
  487. file.setStoragePath(null);
  488. saveFile(file);
  489. saveConflict(file, null);
  490. }
  491. }
  492. }
  493. } else {
  494. return false;
  495. }
  496. return success;
  497. }
  498. public boolean removeFolder(OCFile folder, boolean removeDBData, boolean removeLocalContent) {
  499. boolean success = true;
  500. if (folder != null && folder.isFolder()) {
  501. if (removeDBData && folder.getFileId() != -1) {
  502. success = removeFolderInDb(folder);
  503. }
  504. if (removeLocalContent && success) {
  505. success = removeLocalFolder(folder);
  506. }
  507. } else {
  508. success = false;
  509. }
  510. return success;
  511. }
  512. private boolean removeFolderInDb(OCFile folder) {
  513. Uri folder_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, String.valueOf(folder.getFileId())); // URI
  514. // for recursive deletion
  515. String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + AND + ProviderTableMeta.FILE_PATH + "=?";
  516. String[] whereArgs = new String[]{account.name, folder.getRemotePath()};
  517. int deleted = 0;
  518. if (getContentProviderClient() != null) {
  519. try {
  520. deleted = getContentProviderClient().delete(folder_uri, where, whereArgs);
  521. } catch (RemoteException e) {
  522. Log_OC.d(TAG, e.getMessage(), e);
  523. }
  524. } else {
  525. deleted = getContentResolver().delete(folder_uri, where, whereArgs);
  526. }
  527. return deleted > 0;
  528. }
  529. private boolean removeLocalFolder(OCFile folder) {
  530. boolean success = true;
  531. String localFolderPath = FileStorageUtils.getDefaultSavePathFor(account.name, folder);
  532. File localFolder = new File(localFolderPath);
  533. if (localFolder.exists()) {
  534. // stage 1: remove the local files already registered in the files database
  535. List<OCFile> files = getFolderContent(folder.getFileId(), false);
  536. if (files != null) {
  537. for (OCFile file : files) {
  538. if (file.isFolder()) {
  539. success &= removeLocalFolder(file);
  540. } else {
  541. if (file.isDown()) {
  542. File localFile = new File(file.getStoragePath());
  543. success &= localFile.delete();
  544. if (success) {
  545. // notify MediaScanner about removed file
  546. deleteFileInMediaScan(file.getStoragePath());
  547. file.setStoragePath(null);
  548. saveFile(file);
  549. }
  550. }
  551. }
  552. }
  553. }
  554. // stage 2: remove the folder itself and any local file inside out of sync;
  555. // for instance, after clearing the app cache or reinstalling
  556. success &= removeLocalFolder(localFolder);
  557. }
  558. return success;
  559. }
  560. private boolean removeLocalFolder(File localFolder) {
  561. boolean success = true;
  562. File[] localFiles = localFolder.listFiles();
  563. if (localFiles != null) {
  564. for (File localFile : localFiles) {
  565. if (localFile.isDirectory()) {
  566. success &= removeLocalFolder(localFile);
  567. } else {
  568. success &= localFile.delete();
  569. }
  570. }
  571. }
  572. success &= localFolder.delete();
  573. return success;
  574. }
  575. /**
  576. * Updates database and file system for a file or folder that was moved to a different location.
  577. *
  578. * TODO explore better (faster) implementations
  579. * TODO throw exceptions up !
  580. */
  581. public void moveLocalFile(OCFile file, String targetPath, String targetParentPath) {
  582. if (file != null && file.fileExists() && !OCFile.ROOT_PATH.equals(file.getFileName())) {
  583. OCFile targetParent = getFileByPath(targetParentPath);
  584. if (targetParent == null) {
  585. throw new IllegalStateException("Parent folder of the target path does not exist!!");
  586. }
  587. /// 1. get all the descendants of the moved element in a single QUERY
  588. Cursor c = null;
  589. if (getContentProviderClient() != null) {
  590. try {
  591. c = getContentProviderClient().query(
  592. ProviderTableMeta.CONTENT_URI,
  593. null,
  594. ProviderTableMeta.FILE_ACCOUNT_OWNER + AND + ProviderTableMeta.FILE_PATH + " LIKE ? ",
  595. new String[]{account.name, file.getRemotePath() + "%"},
  596. ProviderTableMeta.FILE_PATH + " ASC "
  597. );
  598. } catch (RemoteException e) {
  599. Log_OC.e(TAG, e.getMessage(), e);
  600. }
  601. } else {
  602. c = getContentResolver().query(
  603. ProviderTableMeta.CONTENT_URI,
  604. null,
  605. ProviderTableMeta.FILE_ACCOUNT_OWNER + AND + ProviderTableMeta.FILE_PATH + " LIKE ? ",
  606. new String[]{account.name, file.getRemotePath() + "%"},
  607. ProviderTableMeta.FILE_PATH + " ASC "
  608. );
  609. }
  610. /// 2. prepare a batch of update operations to change all the descendants
  611. ArrayList<ContentProviderOperation> operations = new ArrayList<>(c.getCount());
  612. String defaultSavePath = FileStorageUtils.getSavePath(account.name);
  613. List<String> originalPathsToTriggerMediaScan = new ArrayList<>();
  614. List<String> newPathsToTriggerMediaScan = new ArrayList<>();
  615. if (c.moveToFirst()) {
  616. int lengthOfOldPath = file.getRemotePath().length();
  617. int lengthOfOldStoragePath = defaultSavePath.length() + lengthOfOldPath;
  618. String[] fileId = new String[1];
  619. do {
  620. ContentValues cv = new ContentValues(); // keep construction in the loop
  621. OCFile child = createFileInstance(c);
  622. cv.put(
  623. ProviderTableMeta.FILE_PATH,
  624. targetPath + child.getRemotePath().substring(lengthOfOldPath)
  625. );
  626. if (child.getStoragePath() != null && child.getStoragePath().startsWith(defaultSavePath)) {
  627. // update link to downloaded content - but local move is not done here!
  628. String targetLocalPath = defaultSavePath + targetPath +
  629. child.getStoragePath().substring(lengthOfOldStoragePath);
  630. cv.put(ProviderTableMeta.FILE_STORAGE_PATH, targetLocalPath);
  631. originalPathsToTriggerMediaScan.add(child.getStoragePath());
  632. newPathsToTriggerMediaScan.add(targetLocalPath);
  633. }
  634. if (child.getRemotePath().equals(file.getRemotePath())) {
  635. cv.put(ProviderTableMeta.FILE_PARENT, targetParent.getFileId());
  636. }
  637. fileId[0] = String.valueOf(child.getFileId());
  638. operations.add(
  639. ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
  640. withValues(cv).
  641. withSelection(ProviderTableMeta._ID + "=?", fileId)
  642. .build());
  643. } while (c.moveToNext());
  644. }
  645. c.close();
  646. /// 3. apply updates in batch
  647. try {
  648. if (getContentResolver() != null) {
  649. getContentResolver().applyBatch(MainApp.getAuthority(), operations);
  650. } else {
  651. getContentProviderClient().applyBatch(operations);
  652. }
  653. } catch (Exception e) {
  654. Log_OC.e(TAG, "Fail to update " + file.getFileId() + " and descendants in database", e);
  655. }
  656. /// 4. move in local file system
  657. String originalLocalPath = FileStorageUtils.getDefaultSavePathFor(account.name, file);
  658. String targetLocalPath = defaultSavePath + targetPath;
  659. File localFile = new File(originalLocalPath);
  660. boolean renamed = false;
  661. if (localFile.exists()) {
  662. File targetFile = new File(targetLocalPath);
  663. File targetFolder = targetFile.getParentFile();
  664. if (!targetFolder.exists() && !targetFolder.mkdirs()) {
  665. Log_OC.e(TAG, "Unable to create parent folder " + targetFolder.getAbsolutePath());
  666. }
  667. renamed = localFile.renameTo(targetFile);
  668. }
  669. if (renamed) {
  670. Iterator<String> it = originalPathsToTriggerMediaScan.iterator();
  671. while (it.hasNext()) {
  672. // Notify MediaScanner about removed file
  673. deleteFileInMediaScan(it.next());
  674. }
  675. it = newPathsToTriggerMediaScan.iterator();
  676. while (it.hasNext()) {
  677. // Notify MediaScanner about new file/folder
  678. triggerMediaScan(it.next());
  679. }
  680. }
  681. }
  682. }
  683. public void copyLocalFile(OCFile file, String targetPath) {
  684. if (file != null && file.fileExists() && !OCFile.ROOT_PATH.equals(file.getFileName())) {
  685. String localPath = FileStorageUtils.getDefaultSavePathFor(account.name, file);
  686. File localFile = new File(localPath);
  687. boolean copied = false;
  688. String defaultSavePath = FileStorageUtils.getSavePath(account.name);
  689. if (localFile.exists()) {
  690. File targetFile = new File(defaultSavePath + targetPath);
  691. File targetFolder = targetFile.getParentFile();
  692. if (!targetFolder.exists() && !targetFolder.mkdirs()) {
  693. Log_OC.e(TAG, "Unable to create parent folder " + targetFolder.getAbsolutePath());
  694. }
  695. copied = FileStorageUtils.copyFile(localFile, targetFile);
  696. }
  697. Log_OC.d(TAG, "Local file COPIED : " + copied);
  698. }
  699. }
  700. public void migrateStoredFiles(String srcPath, String dstPath)
  701. throws RemoteException, OperationApplicationException {
  702. Cursor cursor;
  703. try {
  704. if (getContentResolver() != null) {
  705. cursor = getContentResolver().query(ProviderTableMeta.CONTENT_URI_FILE,
  706. null,
  707. ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL",
  708. null,
  709. null);
  710. } else {
  711. cursor = getContentProviderClient().query(ProviderTableMeta.CONTENT_URI_FILE,
  712. new String[]{ProviderTableMeta._ID, ProviderTableMeta.FILE_STORAGE_PATH},
  713. ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL",
  714. null,
  715. null);
  716. }
  717. } catch (RemoteException e) {
  718. Log_OC.e(TAG, e.getMessage(), e);
  719. throw e;
  720. }
  721. ArrayList<ContentProviderOperation> operations = new ArrayList<>(cursor.getCount());
  722. if (cursor.moveToFirst()) {
  723. String[] fileId = new String[1];
  724. do {
  725. ContentValues cv = new ContentValues();
  726. fileId[0] = String.valueOf(cursor.getLong(cursor.getColumnIndex(ProviderTableMeta._ID)));
  727. String oldFileStoragePath =
  728. cursor.getString(cursor.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH));
  729. if (oldFileStoragePath.startsWith(srcPath)) {
  730. cv.put(ProviderTableMeta.FILE_STORAGE_PATH, oldFileStoragePath.replaceFirst(srcPath, dstPath));
  731. operations.add(
  732. ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
  733. withValues(cv).
  734. withSelection(ProviderTableMeta._ID + "=?", fileId)
  735. .build());
  736. }
  737. } while (cursor.moveToNext());
  738. }
  739. cursor.close();
  740. /// 3. apply updates in batch
  741. if (getContentResolver() != null) {
  742. getContentResolver().applyBatch(MainApp.getAuthority(), operations);
  743. } else {
  744. getContentProviderClient().applyBatch(operations);
  745. }
  746. }
  747. private List<OCFile> getFolderContent(long parentId, boolean onlyOnDevice) {
  748. List<OCFile> ret = new ArrayList<>();
  749. Uri req_uri = Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, String.valueOf(parentId));
  750. Cursor c;
  751. if (getContentProviderClient() != null) {
  752. try {
  753. c = getContentProviderClient().query(
  754. req_uri,
  755. null,
  756. ProviderTableMeta.FILE_PARENT + "=?",
  757. new String[]{String.valueOf(parentId)},
  758. null
  759. );
  760. } catch (RemoteException e) {
  761. Log_OC.e(TAG, e.getMessage(), e);
  762. return ret;
  763. }
  764. } else {
  765. c = getContentResolver().query(
  766. req_uri,
  767. null,
  768. ProviderTableMeta.FILE_PARENT + "=?",
  769. new String[]{String.valueOf(parentId)},
  770. null
  771. );
  772. }
  773. if (c != null) {
  774. if (c.moveToFirst()) {
  775. do {
  776. OCFile child = createFileInstance(c);
  777. if (!onlyOnDevice || child.existsOnDevice()) {
  778. ret.add(child);
  779. }
  780. } while (c.moveToNext());
  781. }
  782. c.close();
  783. }
  784. return ret;
  785. }
  786. private OCFile createRootDir() {
  787. OCFile file = new OCFile(OCFile.ROOT_PATH);
  788. file.setMimeType(MimeType.DIRECTORY);
  789. file.setParentId(FileDataStorageManager.ROOT_PARENT_ID);
  790. saveFile(file);
  791. return file;
  792. }
  793. private boolean fileExists(String cmp_key, String value) {
  794. Cursor c;
  795. if (getContentResolver() != null) {
  796. c = getContentResolver()
  797. .query(ProviderTableMeta.CONTENT_URI,
  798. null,
  799. cmp_key + AND
  800. + ProviderTableMeta.FILE_ACCOUNT_OWNER
  801. + "=?",
  802. new String[]{value, account.name}, null);
  803. } else {
  804. try {
  805. c = getContentProviderClient().query(
  806. ProviderTableMeta.CONTENT_URI,
  807. null,
  808. cmp_key + AND
  809. + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
  810. new String[]{value, account.name}, null);
  811. } catch (RemoteException e) {
  812. Log_OC.e(TAG, "Couldn't determine file existance, assuming non existance: " + e.getMessage(), e);
  813. return false;
  814. }
  815. }
  816. boolean retval = c.moveToFirst();
  817. c.close();
  818. return retval;
  819. }
  820. private Cursor getFileCursorForValue(String key, String value) {
  821. Cursor c;
  822. if (getContentResolver() != null) {
  823. c = getContentResolver()
  824. .query(ProviderTableMeta.CONTENT_URI,
  825. null,
  826. key + AND
  827. + ProviderTableMeta.FILE_ACCOUNT_OWNER
  828. + "=?",
  829. new String[]{value, account.name}, null);
  830. } else {
  831. try {
  832. c = getContentProviderClient().query(
  833. ProviderTableMeta.CONTENT_URI,
  834. null,
  835. key + AND + ProviderTableMeta.FILE_ACCOUNT_OWNER
  836. + "=?", new String[]{value, account.name},
  837. null);
  838. } catch (RemoteException e) {
  839. Log_OC.e(TAG, "Could not get file details: " + e.getMessage(), e);
  840. c = null;
  841. }
  842. }
  843. return c;
  844. }
  845. @Nullable
  846. private OCFile createFileInstanceFromVirtual(Cursor c) {
  847. OCFile file = null;
  848. if (c != null) {
  849. long fileId = c.getLong(c.getColumnIndex(ProviderTableMeta.VIRTUAL_OCFILE_ID));
  850. file = getFileById(fileId);
  851. }
  852. return file;
  853. }
  854. private OCFile createFileInstance(Cursor c) {
  855. OCFile file = null;
  856. if (c != null) {
  857. file = new OCFile(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PATH)));
  858. file.setFileId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID)));
  859. file.setParentId(c.getLong(c.getColumnIndex(ProviderTableMeta.FILE_PARENT)));
  860. file.setEncryptedFileName(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ENCRYPTED_NAME)));
  861. file.setMimeType(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)));
  862. file.setStoragePath(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_STORAGE_PATH)));
  863. if (file.getStoragePath() == null) {
  864. // try to find existing file and bind it with current account;
  865. // with the current update of SynchronizeFolderOperation, this won't be
  866. // necessary anymore after a full synchronization of the account
  867. File f = new File(FileStorageUtils.getDefaultSavePathFor(account.name, file));
  868. if (f.exists()) {
  869. file.setStoragePath(f.getAbsolutePath());
  870. file.setLastSyncDateForData(f.lastModified());
  871. }
  872. }
  873. file.setFileLength(c.getLong(c.getColumnIndex(ProviderTableMeta.FILE_CONTENT_LENGTH)));
  874. file.setCreationTimestamp(c.getLong(c.getColumnIndex(ProviderTableMeta.FILE_CREATION)));
  875. file.setModificationTimestamp(c.getLong(c.getColumnIndex(ProviderTableMeta.FILE_MODIFIED)));
  876. file.setModificationTimestampAtLastSyncForData(c.getLong(
  877. c.getColumnIndex(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA)));
  878. file.setLastSyncDateForProperties(c.getLong(c.getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE)));
  879. file.setLastSyncDateForData(c.getLong(c.getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA)));
  880. file.setEtag(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG)));
  881. file.setEtagOnServer(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG_ON_SERVER)));
  882. file.setSharedViaLink(c.getInt(c.getColumnIndex(ProviderTableMeta.FILE_SHARED_VIA_LINK)) == 1);
  883. file.setSharedWithSharee(c.getInt(c.getColumnIndex(ProviderTableMeta.FILE_SHARED_WITH_SHAREE)) == 1);
  884. file.setPublicLink(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PUBLIC_LINK)));
  885. file.setPermissions(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PERMISSIONS)));
  886. file.setRemoteId(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_REMOTE_ID)));
  887. file.setUpdateThumbnailNeeded(c.getInt(c.getColumnIndex(ProviderTableMeta.FILE_UPDATE_THUMBNAIL)) == 1);
  888. file.setDownloading(c.getInt(c.getColumnIndex(ProviderTableMeta.FILE_IS_DOWNLOADING)) == 1);
  889. file.setEtagInConflict(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG_IN_CONFLICT)));
  890. file.setFavorite(c.getInt(c.getColumnIndex(ProviderTableMeta.FILE_FAVORITE)) == 1);
  891. file.setEncrypted(c.getInt(c.getColumnIndex(ProviderTableMeta.FILE_IS_ENCRYPTED)) == 1);
  892. if (file.isEncrypted()) {
  893. file.setFileName(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_NAME)));
  894. }
  895. file.setMountType(WebdavEntry.MountType.values()[c.getInt(
  896. c.getColumnIndex(ProviderTableMeta.FILE_MOUNT_TYPE))]);
  897. file.setPreviewAvailable(c.getInt(c.getColumnIndex(ProviderTableMeta.FILE_HAS_PREVIEW)) == 1);
  898. file.setUnreadCommentsCount(c.getInt(c.getColumnIndex(ProviderTableMeta.FILE_UNREAD_COMMENTS_COUNT)));
  899. file.setOwnerId(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_OWNER_ID)));
  900. file.setOwnerDisplayName(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_OWNER_DISPLAY_NAME)));
  901. file.setNote(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_NOTE)));
  902. String sharees = c.getString(c.getColumnIndex(ProviderTableMeta.FILE_SHAREES));
  903. if (sharees == null || NULL_STRING.equals(sharees) || sharees.isEmpty()) {
  904. file.setSharees(new ArrayList<>());
  905. } else {
  906. try {
  907. ShareeUser[] shareesArray = new Gson().fromJson(sharees, ShareeUser[].class);
  908. file.setSharees(new ArrayList<>(Arrays.asList(shareesArray)));
  909. } catch (JsonSyntaxException e) {
  910. // ignore saved value due to api change
  911. file.setSharees(new ArrayList<>());
  912. }
  913. }
  914. }
  915. return file;
  916. }
  917. // Methods for Shares
  918. public boolean saveShare(OCShare share) {
  919. boolean overridden = false;
  920. ContentValues cv = new ContentValues();
  921. cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, share.getFileSource());
  922. cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, share.getItemSource());
  923. cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, share.getShareType().getValue());
  924. cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, share.getShareWith());
  925. cv.put(ProviderTableMeta.OCSHARES_PATH, share.getPath());
  926. cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, share.getPermissions());
  927. cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, share.getSharedDate());
  928. cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate());
  929. cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken());
  930. cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME, share.getSharedWithDisplayName());
  931. cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
  932. cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
  933. cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getRemoteId());
  934. cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, account.name);
  935. cv.put(ProviderTableMeta.OCSHARES_IS_PASSWORD_PROTECTED, share.isPasswordProtected() ? 1 : 0);
  936. cv.put(ProviderTableMeta.OCSHARES_NOTE, share.getNote());
  937. cv.put(ProviderTableMeta.OCSHARES_HIDE_DOWNLOAD, share.isHideFileDownload());
  938. if (shareExistsForRemoteId(share.getRemoteId())) {// for renamed files; no more delete and create
  939. overridden = true;
  940. if (getContentResolver() != null) {
  941. getContentResolver().update(ProviderTableMeta.CONTENT_URI_SHARE, cv,
  942. ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
  943. new String[]{String.valueOf(share.getRemoteId())});
  944. } else {
  945. try {
  946. getContentProviderClient().update(ProviderTableMeta.CONTENT_URI_SHARE,
  947. cv, ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
  948. new String[]{String.valueOf(share.getRemoteId())});
  949. } catch (RemoteException e) {
  950. Log_OC.e(TAG, FAILED_TO_INSERT_MSG + e.getMessage(), e);
  951. }
  952. }
  953. } else {
  954. Uri result_uri = null;
  955. if (getContentResolver() != null) {
  956. result_uri = getContentResolver().insert(ProviderTableMeta.CONTENT_URI_SHARE, cv);
  957. } else {
  958. try {
  959. result_uri = getContentProviderClient().insert(ProviderTableMeta.CONTENT_URI_SHARE, cv);
  960. } catch (RemoteException e) {
  961. Log_OC.e(TAG, FAILED_TO_INSERT_MSG + e.getMessage(), e);
  962. }
  963. }
  964. if (result_uri != null) {
  965. long new_id = Long.parseLong(result_uri.getPathSegments().get(1));
  966. share.setId(new_id);
  967. }
  968. }
  969. return overridden;
  970. }
  971. /**
  972. * Retrieves an stored {@link OCShare} given its id.
  973. *
  974. * @param id Identifier.
  975. * @return Stored {@link OCShare} given its id.
  976. */
  977. public OCShare getShareById(long id) {
  978. OCShare share = null;
  979. Cursor c = getShareCursorForValue(ProviderTableMeta._ID, String.valueOf(id));
  980. if (c != null) {
  981. if (c.moveToFirst()) {
  982. share = createShareInstance(c);
  983. }
  984. c.close();
  985. }
  986. return share;
  987. }
  988. /**
  989. * Checks the existance of an stored {@link OCShare} matching the given remote id (not to be confused with
  990. * the local id) in the current account.
  991. *
  992. * @param remoteId Remote of the share in the server.
  993. * @return 'True' if a matching {@link OCShare} is stored in the current account.
  994. */
  995. private boolean shareExistsForRemoteId(long remoteId) {
  996. return shareExistsForValue(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, String.valueOf(remoteId));
  997. }
  998. /**
  999. * Checks the existance of an stored {@link OCShare} in the current account
  1000. * matching a given column and a value for that column
  1001. *
  1002. * @param key Name of the column to match.
  1003. * @param value Value of the column to match.
  1004. * @return 'True' if a matching {@link OCShare} is stored in the current account.
  1005. */
  1006. private boolean shareExistsForValue(String key, String value) {
  1007. Cursor c = getShareCursorForValue(key, value);
  1008. boolean retval = c.moveToFirst();
  1009. c.close();
  1010. return retval;
  1011. }
  1012. /**
  1013. * Gets a {@link Cursor} for an stored {@link OCShare} in the current account
  1014. * matching a given column and a value for that column
  1015. *
  1016. * @param key Name of the column to match.
  1017. * @param value Value of the column to match.
  1018. * @return 'True' if a matching {@link OCShare} is stored in the current account.
  1019. */
  1020. private Cursor getShareCursorForValue(String key, String value) {
  1021. Cursor c;
  1022. if (getContentResolver() != null) {
  1023. c = getContentResolver()
  1024. .query(ProviderTableMeta.CONTENT_URI_SHARE,
  1025. null,
  1026. key + AND
  1027. + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?",
  1028. new String[]{value, account.name},
  1029. null
  1030. );
  1031. } else {
  1032. try {
  1033. c = getContentProviderClient().query(
  1034. ProviderTableMeta.CONTENT_URI_SHARE,
  1035. null,
  1036. key + AND + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?",
  1037. new String[]{value, account.name},
  1038. null
  1039. );
  1040. } catch (RemoteException e) {
  1041. Log_OC.w(TAG, "Could not get details, assuming share does not exist: " + e.getMessage());
  1042. c = null;
  1043. }
  1044. }
  1045. return c;
  1046. }
  1047. /**
  1048. * Get first share bound to a file with a known path and given {@link ShareType}.
  1049. *
  1050. * @param path Path of the file.
  1051. * @param type Type of the share to get
  1052. * @param shareWith Target of the share. Ignored in type is {@link ShareType#PUBLIC_LINK}
  1053. * @return First {@link OCShare} instance found in DB bound to the file in 'path'
  1054. */
  1055. public OCShare getFirstShareByPathAndType(String path, ShareType type, String shareWith) {
  1056. Cursor cursor;
  1057. if (shareWith == null) {
  1058. shareWith = "";
  1059. }
  1060. String selection = ProviderTableMeta.OCSHARES_PATH + AND
  1061. + ProviderTableMeta.OCSHARES_SHARE_TYPE + AND
  1062. + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
  1063. if (!ShareType.PUBLIC_LINK.equals(type)) {
  1064. selection += " AND " + ProviderTableMeta.OCSHARES_SHARE_WITH + "=?";
  1065. }
  1066. String[] selectionArgs;
  1067. if (ShareType.PUBLIC_LINK.equals(type)) {
  1068. selectionArgs = new String[]{
  1069. path,
  1070. Integer.toString(type.getValue()),
  1071. account.name
  1072. };
  1073. } else {
  1074. selectionArgs = new String[]{
  1075. path,
  1076. Integer.toString(type.getValue()),
  1077. account.name,
  1078. shareWith
  1079. };
  1080. }
  1081. if (getContentResolver() != null) {
  1082. cursor = getContentResolver().query(
  1083. ProviderTableMeta.CONTENT_URI_SHARE,
  1084. null,
  1085. selection, selectionArgs,
  1086. null);
  1087. } else {
  1088. try {
  1089. cursor = getContentProviderClient().query(
  1090. ProviderTableMeta.CONTENT_URI_SHARE,
  1091. null,
  1092. selection, selectionArgs,
  1093. null);
  1094. } catch (RemoteException e) {
  1095. Log_OC.e(TAG, "Could not get file details: " + e.getMessage(), e);
  1096. cursor = null;
  1097. }
  1098. }
  1099. OCShare share = null;
  1100. if (cursor != null) {
  1101. if (cursor.moveToFirst()) {
  1102. share = createShareInstance(cursor);
  1103. }
  1104. cursor.close();
  1105. }
  1106. return share;
  1107. }
  1108. private OCShare createShareInstance(Cursor c) {
  1109. OCShare share = null;
  1110. if (c != null) {
  1111. share = new OCShare(c.getString(c.getColumnIndex(ProviderTableMeta.OCSHARES_PATH)));
  1112. share.setId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID)));
  1113. share.setFileSource(c.getLong(c.getColumnIndex(ProviderTableMeta.OCSHARES_ITEM_SOURCE)));
  1114. share.setShareType(ShareType.fromValue(c.getInt(c.getColumnIndex(ProviderTableMeta.OCSHARES_SHARE_TYPE))));
  1115. share.setShareWith(c.getString(c.getColumnIndex(ProviderTableMeta.OCSHARES_SHARE_WITH)));
  1116. share.setPermissions(c.getInt(c.getColumnIndex(ProviderTableMeta.OCSHARES_PERMISSIONS)));
  1117. share.setSharedDate(c.getLong(c.getColumnIndex(ProviderTableMeta.OCSHARES_SHARED_DATE)));
  1118. share.setExpirationDate(c.getLong(c.getColumnIndex(ProviderTableMeta.OCSHARES_EXPIRATION_DATE)));
  1119. share.setToken(c.getString(c.getColumnIndex(ProviderTableMeta.OCSHARES_TOKEN)));
  1120. share.setSharedWithDisplayName(
  1121. c.getString(c.getColumnIndex(ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME)));
  1122. share.setFolder(c.getInt(c.getColumnIndex(ProviderTableMeta.OCSHARES_IS_DIRECTORY)) == 1);
  1123. share.setUserId(c.getString(c.getColumnIndex(ProviderTableMeta.OCSHARES_USER_ID)));
  1124. share.setRemoteId(c.getLong(c.getColumnIndex(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED)));
  1125. share.setPasswordProtected(c.getInt(c.getColumnIndex(ProviderTableMeta.OCSHARES_IS_PASSWORD_PROTECTED)) == 1);
  1126. share.setNote(c.getString(c.getColumnIndex(ProviderTableMeta.OCSHARES_NOTE)));
  1127. share.setHideFileDownload(c.getInt(c.getColumnIndex(ProviderTableMeta.OCSHARES_HIDE_DOWNLOAD)) == 1);
  1128. }
  1129. return share;
  1130. }
  1131. private void resetShareFlagsInAllFiles() {
  1132. ContentValues cv = new ContentValues();
  1133. cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, false);
  1134. cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, false);
  1135. cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
  1136. String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
  1137. String[] whereArgs = new String[]{account.name};
  1138. if (getContentResolver() != null) {
  1139. getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
  1140. } else {
  1141. try {
  1142. getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
  1143. } catch (RemoteException e) {
  1144. Log_OC.e(TAG, "Exception in resetShareFlagsInAllFiles" + e.getMessage(), e);
  1145. }
  1146. }
  1147. }
  1148. private void resetShareFlagsInFolder(OCFile folder) {
  1149. ContentValues cv = new ContentValues();
  1150. cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, false);
  1151. cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, false);
  1152. cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
  1153. String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + AND + ProviderTableMeta.FILE_PARENT + "=?";
  1154. String[] whereArgs = new String[]{account.name, String.valueOf(folder.getFileId())};
  1155. if (getContentResolver() != null) {
  1156. getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
  1157. } else {
  1158. try {
  1159. getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
  1160. } catch (RemoteException e) {
  1161. Log_OC.e(TAG, "Exception in resetShareFlagsInFolder " + e.getMessage(), e);
  1162. }
  1163. }
  1164. }
  1165. private void resetShareFlagInAFile(String filePath) {
  1166. ContentValues cv = new ContentValues();
  1167. cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, false);
  1168. cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, false);
  1169. cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, "");
  1170. String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + AND + ProviderTableMeta.FILE_PATH + "=?";
  1171. String[] whereArgs = new String[]{account.name, filePath};
  1172. if (getContentResolver() != null) {
  1173. getContentResolver().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
  1174. } else {
  1175. try {
  1176. getContentProviderClient().update(ProviderTableMeta.CONTENT_URI, cv, where, whereArgs);
  1177. } catch (RemoteException e) {
  1178. Log_OC.e(TAG, "Exception in resetShareFlagsInFolder " + e.getMessage(), e);
  1179. }
  1180. }
  1181. }
  1182. private void cleanShares() {
  1183. String where = ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
  1184. String[] whereArgs = new String[]{account.name};
  1185. if (getContentResolver() != null) {
  1186. getContentResolver().delete(ProviderTableMeta.CONTENT_URI_SHARE, where, whereArgs);
  1187. } else {
  1188. try {
  1189. getContentProviderClient().delete(ProviderTableMeta.CONTENT_URI_SHARE, where, whereArgs);
  1190. } catch (RemoteException e) {
  1191. Log_OC.e(TAG, "Exception in cleanShares" + e.getMessage(), e);
  1192. }
  1193. }
  1194. }
  1195. public void saveShares(Collection<OCShare> shares) {
  1196. cleanShares();
  1197. if (shares != null) {
  1198. ArrayList<ContentProviderOperation> operations =
  1199. new ArrayList<ContentProviderOperation>(shares.size());
  1200. // prepare operations to insert or update files to save in the given folder
  1201. for (OCShare share : shares) {
  1202. ContentValues cv = new ContentValues();
  1203. cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, share.getFileSource());
  1204. cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, share.getItemSource());
  1205. cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, share.getShareType().getValue());
  1206. cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, share.getShareWith());
  1207. cv.put(ProviderTableMeta.OCSHARES_PATH, share.getPath());
  1208. cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, share.getPermissions());
  1209. cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, share.getSharedDate());
  1210. cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate());
  1211. cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken());
  1212. cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME, share.getSharedWithDisplayName());
  1213. cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
  1214. cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
  1215. cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getRemoteId());
  1216. cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, account.name);
  1217. cv.put(ProviderTableMeta.OCSHARES_IS_PASSWORD_PROTECTED, share.isPasswordProtected() ? 1 : 0);
  1218. cv.put(ProviderTableMeta.OCSHARES_NOTE, share.getNote());
  1219. cv.put(ProviderTableMeta.OCSHARES_HIDE_DOWNLOAD, share.isHideFileDownload());
  1220. if (shareExistsForRemoteId(share.getRemoteId())) {
  1221. // updating an existing file
  1222. operations.add(
  1223. ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI_SHARE).
  1224. withValues(cv).
  1225. withSelection(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + "=?",
  1226. new String[]{String.valueOf(share.getRemoteId())})
  1227. .build());
  1228. } else {
  1229. // adding a new file
  1230. operations.add(
  1231. ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI_SHARE).
  1232. withValues(cv).
  1233. build()
  1234. );
  1235. }
  1236. }
  1237. // apply operations in batch
  1238. if (operations.size() > 0) {
  1239. @SuppressWarnings("unused")
  1240. ContentProviderResult[] results = null;
  1241. Log_OC.d(TAG, String.format(Locale.ENGLISH, SENDING_TO_FILECONTENTPROVIDER_MSG, operations.size()));
  1242. try {
  1243. if (getContentResolver() != null) {
  1244. results = getContentResolver().applyBatch(MainApp.getAuthority(),
  1245. operations);
  1246. } else {
  1247. results = getContentProviderClient().applyBatch(operations);
  1248. }
  1249. } catch (OperationApplicationException | RemoteException e) {
  1250. Log_OC.e(TAG, EXCEPTION_MSG + e.getMessage(), e);
  1251. }
  1252. }
  1253. }
  1254. }
  1255. public void updateSharedFiles(Collection<OCFile> sharedFiles) {
  1256. resetShareFlagsInAllFiles();
  1257. if (sharedFiles != null) {
  1258. ArrayList<ContentProviderOperation> operations = new ArrayList<>(sharedFiles.size());
  1259. // prepare operations to insert or update files to save in the given folder
  1260. for (OCFile file : sharedFiles) {
  1261. ContentValues cv = new ContentValues();
  1262. cv.put(ProviderTableMeta.FILE_MODIFIED, file.getModificationTimestamp());
  1263. cv.put(
  1264. ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA,
  1265. file.getModificationTimestampAtLastSyncForData()
  1266. );
  1267. cv.put(ProviderTableMeta.FILE_CREATION, file.getCreationTimestamp());
  1268. cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, file.getFileLength());
  1269. cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, file.getMimeType());
  1270. cv.put(ProviderTableMeta.FILE_NAME, file.getFileName());
  1271. cv.put(ProviderTableMeta.FILE_PARENT, file.getParentId());
  1272. cv.put(ProviderTableMeta.FILE_PATH, file.getRemotePath());
  1273. if (!file.isFolder()) {
  1274. cv.put(ProviderTableMeta.FILE_STORAGE_PATH, file.getStoragePath());
  1275. }
  1276. cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, account.name);
  1277. cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
  1278. cv.put(
  1279. ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA,
  1280. file.getLastSyncDateForData()
  1281. );
  1282. cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
  1283. cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, file.getEtagOnServer());
  1284. cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0);
  1285. cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0);
  1286. cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
  1287. cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
  1288. cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
  1289. cv.put(ProviderTableMeta.FILE_FAVORITE, file.isFavorite());
  1290. cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.isUpdateThumbnailNeeded() ? 1 : 0);
  1291. cv.put(ProviderTableMeta.FILE_IS_DOWNLOADING, file.isDownloading() ? 1 : 0);
  1292. cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, file.getEtagInConflict());
  1293. boolean existsByPath = fileExists(file.getRemotePath());
  1294. if (existsByPath || fileExists(file.getFileId())) {
  1295. // updating an existing file
  1296. operations.add(
  1297. ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI).
  1298. withValues(cv).
  1299. withSelection(ProviderTableMeta._ID + "=?",
  1300. new String[]{String.valueOf(file.getFileId())})
  1301. .build());
  1302. } else {
  1303. // adding a new file
  1304. operations.add(
  1305. ContentProviderOperation.newInsert(ProviderTableMeta.CONTENT_URI).
  1306. withValues(cv).
  1307. build()
  1308. );
  1309. }
  1310. }
  1311. // apply operations in batch
  1312. if (operations.size() > 0) {
  1313. @SuppressWarnings("unused")
  1314. ContentProviderResult[] results = null;
  1315. Log_OC.d(TAG, String.format(Locale.ENGLISH, SENDING_TO_FILECONTENTPROVIDER_MSG, operations.size()));
  1316. try {
  1317. if (getContentResolver() != null) {
  1318. results = getContentResolver().applyBatch(MainApp.getAuthority(), operations);
  1319. } else {
  1320. results = getContentProviderClient().applyBatch(operations);
  1321. }
  1322. } catch (OperationApplicationException | RemoteException e) {
  1323. Log_OC.e(TAG, EXCEPTION_MSG + e.getMessage(), e);
  1324. }
  1325. }
  1326. }
  1327. }
  1328. public void removeShare(OCShare share) {
  1329. Uri share_uri = ProviderTableMeta.CONTENT_URI_SHARE;
  1330. String where = ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + AND +
  1331. ProviderTableMeta._ID + "=?";
  1332. String[] whereArgs = new String[]{account.name, Long.toString(share.getId())};
  1333. if (getContentProviderClient() != null) {
  1334. try {
  1335. getContentProviderClient().delete(share_uri, where, whereArgs);
  1336. } catch (RemoteException e) {
  1337. Log_OC.d(TAG, e.getMessage(), e);
  1338. }
  1339. } else {
  1340. getContentResolver().delete(share_uri, where, whereArgs);
  1341. }
  1342. }
  1343. public void saveSharesDB(List<OCShare> shares) {
  1344. ArrayList<ContentProviderOperation> operations = new ArrayList<>();
  1345. // Reset flags & Remove shares for this files
  1346. String filePath = "";
  1347. for (OCShare share : shares) {
  1348. if (!filePath.equals(share.getPath())) {
  1349. filePath = share.getPath();
  1350. resetShareFlagInAFile(filePath);
  1351. operations = prepareRemoveSharesInFile(filePath, operations);
  1352. }
  1353. }
  1354. // Add operations to insert shares
  1355. operations = prepareInsertShares(shares, operations);
  1356. // apply operations in batch
  1357. if (operations.size() > 0) {
  1358. Log_OC.d(TAG, String.format(Locale.ENGLISH, SENDING_TO_FILECONTENTPROVIDER_MSG, operations.size()));
  1359. try {
  1360. if (getContentResolver() != null) {
  1361. getContentResolver().applyBatch(MainApp.getAuthority(), operations);
  1362. } else {
  1363. getContentProviderClient().applyBatch(operations);
  1364. }
  1365. } catch (OperationApplicationException | RemoteException e) {
  1366. Log_OC.e(TAG, EXCEPTION_MSG + e.getMessage(), e);
  1367. }
  1368. }
  1369. // // TODO: review if it is needed
  1370. // // Update shared files
  1371. // ArrayList<OCFile> sharedFiles = new ArrayList<OCFile>();
  1372. //
  1373. // for (OCShare share : shares) {
  1374. // // Get the path
  1375. // String path = share.getPath();
  1376. // if (share.isFolder()) {
  1377. // path = path + FileUtils.PATH_SEPARATOR;
  1378. // }
  1379. //
  1380. // // Update OCFile with data from share: ShareByLink, publicLink and
  1381. // OCFile file = getFileByPath(path);
  1382. // if (file != null) {
  1383. // if (share.getShareType().equals(ShareType.PUBLIC_LINK)) {
  1384. // file.setShareViaLink(true);
  1385. // sharedFiles.add(file);
  1386. // }
  1387. // }
  1388. // }
  1389. //
  1390. // // TODO: Review
  1391. // updateSharedFiles(sharedFiles);
  1392. }
  1393. public void removeSharesForFile(String remotePath) {
  1394. resetShareFlagInAFile(remotePath);
  1395. ArrayList<ContentProviderOperation> operations = new ArrayList<>();
  1396. operations = prepareRemoveSharesInFile(remotePath, operations);
  1397. // apply operations in batch
  1398. if (operations.size() > 0) {
  1399. Log_OC.d(TAG, String.format(Locale.ENGLISH, SENDING_TO_FILECONTENTPROVIDER_MSG, operations.size()));
  1400. try {
  1401. if (getContentResolver() != null) {
  1402. getContentResolver().applyBatch(MainApp.getAuthority(), operations);
  1403. } else {
  1404. getContentProviderClient().applyBatch(operations);
  1405. }
  1406. } catch (OperationApplicationException | RemoteException e) {
  1407. Log_OC.e(TAG, EXCEPTION_MSG + e.getMessage(), e);
  1408. }
  1409. }
  1410. }
  1411. public void saveSharesInFolder(ArrayList<OCShare> shares, OCFile folder) {
  1412. resetShareFlagsInFolder(folder);
  1413. ArrayList<ContentProviderOperation> operations = new ArrayList<>();
  1414. operations = prepareRemoveSharesInFolder(folder, operations);
  1415. if (shares != null) {
  1416. // prepare operations to insert or update files to save in the given folder
  1417. operations = prepareInsertShares(shares, operations);
  1418. }
  1419. // apply operations in batch
  1420. if (operations.size() > 0) {
  1421. Log_OC.d(TAG, String.format(Locale.ENGLISH, SENDING_TO_FILECONTENTPROVIDER_MSG, operations.size()));
  1422. try {
  1423. if (getContentResolver() != null) {
  1424. getContentResolver().applyBatch(MainApp.getAuthority(), operations);
  1425. } else {
  1426. getContentProviderClient().applyBatch(operations);
  1427. }
  1428. } catch (OperationApplicationException | RemoteException e) {
  1429. Log_OC.e(TAG, EXCEPTION_MSG + e.getMessage(), e);
  1430. }
  1431. }
  1432. }
  1433. /**
  1434. * Prepare operations to insert or update files to save in the given folder
  1435. * @param shares List of shares to insert
  1436. * @param operations List of operations
  1437. * @return
  1438. */
  1439. private ArrayList<ContentProviderOperation> prepareInsertShares(
  1440. List<OCShare> shares, ArrayList<ContentProviderOperation> operations) {
  1441. if (shares != null) {
  1442. ContentValues cv;
  1443. // prepare operations to insert or update files to save in the given folder
  1444. for (OCShare share : shares) {
  1445. cv = new ContentValues();
  1446. cv.put(ProviderTableMeta.OCSHARES_FILE_SOURCE, share.getFileSource());
  1447. cv.put(ProviderTableMeta.OCSHARES_ITEM_SOURCE, share.getItemSource());
  1448. cv.put(ProviderTableMeta.OCSHARES_SHARE_TYPE, share.getShareType().getValue());
  1449. cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH, share.getShareWith());
  1450. cv.put(ProviderTableMeta.OCSHARES_PATH, share.getPath());
  1451. cv.put(ProviderTableMeta.OCSHARES_PERMISSIONS, share.getPermissions());
  1452. cv.put(ProviderTableMeta.OCSHARES_SHARED_DATE, share.getSharedDate());
  1453. cv.put(ProviderTableMeta.OCSHARES_EXPIRATION_DATE, share.getExpirationDate());
  1454. cv.put(ProviderTableMeta.OCSHARES_TOKEN, share.getToken());
  1455. cv.put(ProviderTableMeta.OCSHARES_SHARE_WITH_DISPLAY_NAME, share.getSharedWithDisplayName());
  1456. cv.put(ProviderTableMeta.OCSHARES_IS_DIRECTORY, share.isFolder() ? 1 : 0);
  1457. cv.put(ProviderTableMeta.OCSHARES_USER_ID, share.getUserId());
  1458. cv.put(ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED, share.getRemoteId());
  1459. cv.put(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER, account.name);
  1460. cv.put(ProviderTableMeta.OCSHARES_IS_PASSWORD_PROTECTED, share.isPasswordProtected() ? 1 : 0);
  1461. cv.put(ProviderTableMeta.OCSHARES_NOTE, share.getNote());
  1462. cv.put(ProviderTableMeta.OCSHARES_HIDE_DOWNLOAD, share.isHideFileDownload());
  1463. // adding a new share resource
  1464. operations.add(ContentProviderOperation.newInsert(
  1465. ProviderTableMeta.CONTENT_URI_SHARE).withValues(cv).build());
  1466. }
  1467. }
  1468. return operations;
  1469. }
  1470. private ArrayList<ContentProviderOperation> prepareRemoveSharesInFolder(
  1471. OCFile folder, ArrayList<ContentProviderOperation> preparedOperations) {
  1472. if (folder != null) {
  1473. String where = ProviderTableMeta.OCSHARES_PATH + AND
  1474. + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
  1475. String[] whereArgs = new String[]{"", account.name};
  1476. List<OCFile> files = getFolderContent(folder, false);
  1477. for (OCFile file : files) {
  1478. whereArgs[0] = file.getRemotePath();
  1479. preparedOperations.add(
  1480. ContentProviderOperation.newDelete(ProviderTableMeta.CONTENT_URI_SHARE).
  1481. withSelection(where, whereArgs).
  1482. build()
  1483. );
  1484. }
  1485. }
  1486. return preparedOperations;
  1487. }
  1488. private ArrayList<ContentProviderOperation> prepareRemoveSharesInFile(
  1489. String filePath, ArrayList<ContentProviderOperation> preparedOperations) {
  1490. String where = ProviderTableMeta.OCSHARES_PATH + AND
  1491. + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + "=?";
  1492. String[] whereArgs = new String[]{filePath, account.name};
  1493. preparedOperations.add(
  1494. ContentProviderOperation.newDelete(ProviderTableMeta.CONTENT_URI_SHARE).
  1495. withSelection(where, whereArgs).
  1496. build()
  1497. );
  1498. return preparedOperations;
  1499. }
  1500. public List<OCShare> getSharesWithForAFile(String filePath, String accountName) {
  1501. // Condition
  1502. String where = ProviderTableMeta.OCSHARES_PATH + AND
  1503. + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + AND
  1504. + " (" + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? OR "
  1505. + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? OR "
  1506. + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? OR "
  1507. + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? OR "
  1508. + ProviderTableMeta.OCSHARES_SHARE_TYPE + "=? ) ";
  1509. String[] whereArgs = new String[]{filePath, accountName,
  1510. Integer.toString(ShareType.USER.getValue()),
  1511. Integer.toString(ShareType.GROUP.getValue()),
  1512. Integer.toString(ShareType.EMAIL.getValue()),
  1513. Integer.toString(ShareType.FEDERATED.getValue()),
  1514. Integer.toString(ShareType.ROOM.getValue())};
  1515. Cursor cursor = null;
  1516. if (getContentResolver() != null) {
  1517. cursor = getContentResolver().query(ProviderTableMeta.CONTENT_URI_SHARE, null, where, whereArgs, null);
  1518. } else {
  1519. try {
  1520. cursor = getContentProviderClient().query(ProviderTableMeta.CONTENT_URI_SHARE, null, where,
  1521. whereArgs, null);
  1522. } catch (RemoteException e) {
  1523. Log_OC.e(TAG, "Could not get list of shares with: " + e.getMessage(), e);
  1524. cursor = null;
  1525. }
  1526. }
  1527. ArrayList<OCShare> shares = new ArrayList<>();
  1528. OCShare share;
  1529. if (cursor != null) {
  1530. if (cursor.moveToFirst()) {
  1531. do {
  1532. share = createShareInstance(cursor);
  1533. shares.add(share);
  1534. } while (cursor.moveToNext());
  1535. }
  1536. cursor.close();
  1537. }
  1538. return shares;
  1539. }
  1540. public static void triggerMediaScan(String path) {
  1541. if (path != null) {
  1542. Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
  1543. intent.setData(Uri.fromFile(new File(path)));
  1544. MainApp.getAppContext().sendBroadcast(intent);
  1545. }
  1546. }
  1547. public void deleteFileInMediaScan(String path) {
  1548. String mimetypeString = FileStorageUtils.getMimeTypeFromName(path);
  1549. ContentResolver contentResolver = getContentResolver();
  1550. if (contentResolver != null) {
  1551. if (MimeTypeUtil.isImage(mimetypeString)) {
  1552. // Images
  1553. contentResolver.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
  1554. MediaStore.Images.Media.DATA + "=?", new String[]{path});
  1555. } else if (MimeTypeUtil.isAudio(mimetypeString)) {
  1556. // Audio
  1557. contentResolver.delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
  1558. MediaStore.Audio.Media.DATA + "=?", new String[]{path});
  1559. } else if (MimeTypeUtil.isVideo(mimetypeString)) {
  1560. // Video
  1561. contentResolver.delete(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
  1562. MediaStore.Video.Media.DATA + "=?", new String[]{path});
  1563. }
  1564. } else {
  1565. ContentProviderClient contentProviderClient = getContentProviderClient();
  1566. try {
  1567. if (MimeTypeUtil.isImage(mimetypeString)) {
  1568. // Images
  1569. contentProviderClient.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
  1570. MediaStore.Images.Media.DATA + "=?", new String[]{path});
  1571. } else if (MimeTypeUtil.isAudio(mimetypeString)) {
  1572. // Audio
  1573. contentProviderClient.delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
  1574. MediaStore.Audio.Media.DATA + "=?", new String[]{path});
  1575. } else if (MimeTypeUtil.isVideo(mimetypeString)) {
  1576. // Video
  1577. contentProviderClient.delete(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
  1578. MediaStore.Video.Media.DATA + "=?", new String[]{path});
  1579. }
  1580. } catch (RemoteException e) {
  1581. Log_OC.e(TAG, "Exception deleting media file in MediaStore " + e.getMessage(), e);
  1582. }
  1583. }
  1584. }
  1585. public void saveConflict(OCFile file, String etagInConflict) {
  1586. if (!file.isDown()) {
  1587. etagInConflict = null;
  1588. }
  1589. ContentValues cv = new ContentValues();
  1590. cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, etagInConflict);
  1591. int updated = 0;
  1592. if (getContentResolver() != null) {
  1593. updated = getContentResolver().update(
  1594. ProviderTableMeta.CONTENT_URI_FILE,
  1595. cv,
  1596. ProviderTableMeta._ID + "=?",
  1597. new String[]{String.valueOf(file.getFileId())}
  1598. );
  1599. } else {
  1600. try {
  1601. updated = getContentProviderClient().update(
  1602. ProviderTableMeta.CONTENT_URI_FILE,
  1603. cv,
  1604. ProviderTableMeta._ID + "=?",
  1605. new String[]{String.valueOf(file.getFileId())}
  1606. );
  1607. } catch (RemoteException e) {
  1608. Log_OC.e(TAG, "Failed saving conflict in database " + e.getMessage(), e);
  1609. }
  1610. }
  1611. Log_OC.d(TAG, "Number of files updated with CONFLICT: " + updated);
  1612. if (updated > 0) {
  1613. if (etagInConflict != null) {
  1614. /// set conflict in all ancestor folders
  1615. long parentId = file.getParentId();
  1616. Set<String> ancestorIds = new HashSet<>();
  1617. while (parentId != FileDataStorageManager.ROOT_PARENT_ID) {
  1618. ancestorIds.add(Long.toString(parentId));
  1619. parentId = getFileById(parentId).getParentId();
  1620. }
  1621. if (ancestorIds.size() > 0) {
  1622. final StringBuffer whereBuffer = new StringBuffer();
  1623. whereBuffer.append(ProviderTableMeta._ID).append(" IN (");
  1624. for (int i = 0; i < ancestorIds.size() - 1; i++) {
  1625. whereBuffer.append("?,");
  1626. }
  1627. whereBuffer.append("?)");
  1628. if (getContentResolver() != null) {
  1629. updated = getContentResolver().update(
  1630. ProviderTableMeta.CONTENT_URI_FILE,
  1631. cv,
  1632. whereBuffer.toString(),
  1633. ancestorIds.toArray(new String[]{})
  1634. );
  1635. } else {
  1636. try {
  1637. updated = getContentProviderClient().update(
  1638. ProviderTableMeta.CONTENT_URI_FILE,
  1639. cv,
  1640. whereBuffer.toString(),
  1641. ancestorIds.toArray(new String[]{})
  1642. );
  1643. } catch (RemoteException e) {
  1644. Log_OC.e(TAG, "Failed saving conflict in database " + e.getMessage(), e);
  1645. }
  1646. }
  1647. } // else file is ROOT folder, no parent to set in conflict
  1648. } else {
  1649. /// update conflict in ancestor folders
  1650. // (not directly unset; maybe there are more conflicts below them)
  1651. String parentPath = file.getRemotePath();
  1652. if (parentPath.endsWith(OCFile.PATH_SEPARATOR)) {
  1653. parentPath = parentPath.substring(0, parentPath.length() - 1);
  1654. }
  1655. parentPath = parentPath.substring(0, parentPath.lastIndexOf(OCFile.PATH_SEPARATOR) + 1);
  1656. Log_OC.d(TAG, "checking parents to remove conflict; STARTING with " + parentPath);
  1657. String[] projection = new String[]{ProviderTableMeta._ID};
  1658. while (parentPath.length() > 0) {
  1659. String whereForDescencentsInConflict =
  1660. ProviderTableMeta.FILE_ETAG_IN_CONFLICT + " IS NOT NULL AND " +
  1661. ProviderTableMeta.FILE_CONTENT_TYPE + " != 'DIR' AND " +
  1662. ProviderTableMeta.FILE_ACCOUNT_OWNER + AND +
  1663. ProviderTableMeta.FILE_PATH + " LIKE ?";
  1664. Cursor descendentsInConflict = null;
  1665. if (getContentResolver() != null) {
  1666. descendentsInConflict = getContentResolver().query(
  1667. ProviderTableMeta.CONTENT_URI_FILE,
  1668. projection,
  1669. whereForDescencentsInConflict,
  1670. new String[]{account.name, parentPath + "%"},
  1671. null
  1672. );
  1673. } else {
  1674. try {
  1675. descendentsInConflict = getContentProviderClient().query(
  1676. ProviderTableMeta.CONTENT_URI_FILE,
  1677. projection,
  1678. whereForDescencentsInConflict,
  1679. new String[]{account.name, parentPath + "%"},
  1680. null
  1681. );
  1682. } catch (RemoteException e) {
  1683. Log_OC.e(TAG, "Failed querying for descendents in conflict " + e.getMessage(), e);
  1684. }
  1685. }
  1686. if (descendentsInConflict == null || descendentsInConflict.getCount() == 0) {
  1687. Log_OC.d(TAG, "NO MORE conflicts in " + parentPath);
  1688. if (getContentResolver() != null) {
  1689. updated = getContentResolver().update(
  1690. ProviderTableMeta.CONTENT_URI_FILE,
  1691. cv,
  1692. ProviderTableMeta.FILE_ACCOUNT_OWNER + AND +
  1693. ProviderTableMeta.FILE_PATH + "=?",
  1694. new String[]{account.name, parentPath}
  1695. );
  1696. } else {
  1697. try {
  1698. updated = getContentProviderClient().update(
  1699. ProviderTableMeta.CONTENT_URI_FILE,
  1700. cv,
  1701. ProviderTableMeta.FILE_ACCOUNT_OWNER + AND +
  1702. ProviderTableMeta.FILE_PATH + "=?"
  1703. , new String[]{account.name, parentPath}
  1704. );
  1705. } catch (RemoteException e) {
  1706. Log_OC.e(TAG, "Failed saving conflict in database " + e.getMessage(), e);
  1707. }
  1708. }
  1709. } else {
  1710. Log_OC.d(TAG, "STILL " + descendentsInConflict.getCount() + " in " + parentPath);
  1711. }
  1712. if (descendentsInConflict != null) {
  1713. descendentsInConflict.close();
  1714. }
  1715. parentPath = parentPath.substring(0, parentPath.length() - 1); // trim last /
  1716. parentPath = parentPath.substring(0, parentPath.lastIndexOf(OCFile.PATH_SEPARATOR) + 1);
  1717. Log_OC.d(TAG, "checking parents to remove conflict; NEXT " + parentPath);
  1718. }
  1719. }
  1720. }
  1721. }
  1722. public OCCapability saveCapabilities(OCCapability capability) {
  1723. // Prepare capabilities data
  1724. ContentValues cv = createContentValues(account.name, capability);
  1725. if (capabilityExists(account.name)) {
  1726. if (getContentResolver() != null) {
  1727. getContentResolver().update(ProviderTableMeta.CONTENT_URI_CAPABILITIES, cv,
  1728. ProviderTableMeta.CAPABILITIES_ACCOUNT_NAME + "=?",
  1729. new String[]{account.name});
  1730. } else {
  1731. try {
  1732. getContentProviderClient().update(ProviderTableMeta.CONTENT_URI_CAPABILITIES,
  1733. cv, ProviderTableMeta.CAPABILITIES_ACCOUNT_NAME + "=?",
  1734. new String[]{account.name});
  1735. } catch (RemoteException e) {
  1736. Log_OC.e(TAG, FAILED_TO_INSERT_MSG + e.getMessage(), e);
  1737. }
  1738. }
  1739. } else {
  1740. Uri result_uri = null;
  1741. if (getContentResolver() != null) {
  1742. result_uri = getContentResolver().insert(
  1743. ProviderTableMeta.CONTENT_URI_CAPABILITIES, cv);
  1744. } else {
  1745. try {
  1746. result_uri = getContentProviderClient().insert(
  1747. ProviderTableMeta.CONTENT_URI_CAPABILITIES, cv);
  1748. } catch (RemoteException e) {
  1749. Log_OC.e(TAG, FAILED_TO_INSERT_MSG + e.getMessage(), e);
  1750. }
  1751. }
  1752. if (result_uri != null) {
  1753. long new_id = Long.parseLong(result_uri.getPathSegments()
  1754. .get(1));
  1755. capability.setId(new_id);
  1756. capability.setAccountName(account.name);
  1757. }
  1758. }
  1759. return capability;
  1760. }
  1761. @NotNull
  1762. private ContentValues createContentValues(String accountName, OCCapability capability) {
  1763. ContentValues cv = new ContentValues();
  1764. cv.put(ProviderTableMeta.CAPABILITIES_ACCOUNT_NAME, accountName);
  1765. cv.put(ProviderTableMeta.CAPABILITIES_VERSION_MAYOR, capability.getVersionMayor());
  1766. cv.put(ProviderTableMeta.CAPABILITIES_VERSION_MINOR, capability.getVersionMinor());
  1767. cv.put(ProviderTableMeta.CAPABILITIES_VERSION_MICRO, capability.getVersionMicro());
  1768. cv.put(ProviderTableMeta.CAPABILITIES_VERSION_STRING, capability.getVersionString());
  1769. cv.put(ProviderTableMeta.CAPABILITIES_VERSION_EDITION, capability.getVersionEdition());
  1770. cv.put(ProviderTableMeta.CAPABILITIES_EXTENDED_SUPPORT, capability.getExtendedSupport().getValue());
  1771. cv.put(ProviderTableMeta.CAPABILITIES_CORE_POLLINTERVAL, capability.getCorePollInterval());
  1772. cv.put(ProviderTableMeta.CAPABILITIES_SHARING_API_ENABLED, capability.getFilesSharingApiEnabled().getValue());
  1773. cv.put(ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_ENABLED,
  1774. capability.getFilesSharingPublicEnabled().getValue());
  1775. cv.put(ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_PASSWORD_ENFORCED,
  1776. capability.getFilesSharingPublicPasswordEnforced().getValue());
  1777. cv.put(ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_ASK_FOR_OPTIONAL_PASSWORD,
  1778. capability.getFilesSharingPublicAskForOptionalPassword().getValue());
  1779. cv.put(ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_EXPIRE_DATE_ENABLED,
  1780. capability.getFilesSharingPublicExpireDateEnabled().getValue());
  1781. cv.put(ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_EXPIRE_DATE_DAYS,
  1782. capability.getFilesSharingPublicExpireDateDays());
  1783. cv.put(ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_EXPIRE_DATE_ENFORCED,
  1784. capability.getFilesSharingPublicExpireDateEnforced().getValue());
  1785. cv.put(ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_SEND_MAIL,
  1786. capability.getFilesSharingPublicSendMail().getValue());
  1787. cv.put(ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_UPLOAD,
  1788. capability.getFilesSharingPublicUpload().getValue());
  1789. cv.put(ProviderTableMeta.CAPABILITIES_SHARING_USER_SEND_MAIL,
  1790. capability.getFilesSharingUserSendMail().getValue());
  1791. cv.put(ProviderTableMeta.CAPABILITIES_SHARING_RESHARING, capability.getFilesSharingResharing().getValue());
  1792. cv.put(ProviderTableMeta.CAPABILITIES_SHARING_FEDERATION_OUTGOING,
  1793. capability.getFilesSharingFederationOutgoing().getValue());
  1794. cv.put(ProviderTableMeta.CAPABILITIES_SHARING_FEDERATION_INCOMING,
  1795. capability.getFilesSharingFederationIncoming().getValue());
  1796. cv.put(ProviderTableMeta.CAPABILITIES_FILES_BIGFILECHUNKING, capability.getFilesBigFileChunking().getValue());
  1797. cv.put(ProviderTableMeta.CAPABILITIES_FILES_UNDELETE, capability.getFilesUndelete().getValue());
  1798. cv.put(ProviderTableMeta.CAPABILITIES_FILES_VERSIONING, capability.getFilesVersioning().getValue());
  1799. cv.put(ProviderTableMeta.CAPABILITIES_FILES_DROP, capability.getFilesFileDrop().getValue());
  1800. cv.put(ProviderTableMeta.CAPABILITIES_EXTERNAL_LINKS, capability.getExternalLinks().getValue());
  1801. cv.put(ProviderTableMeta.CAPABILITIES_SERVER_NAME, capability.getServerName());
  1802. cv.put(ProviderTableMeta.CAPABILITIES_SERVER_COLOR, capability.getServerColor());
  1803. cv.put(ProviderTableMeta.CAPABILITIES_SERVER_TEXT_COLOR, capability.getServerTextColor());
  1804. cv.put(ProviderTableMeta.CAPABILITIES_SERVER_ELEMENT_COLOR, capability.getServerElementColor());
  1805. cv.put(ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_URL, capability.getServerBackground());
  1806. cv.put(ProviderTableMeta.CAPABILITIES_SERVER_SLOGAN, capability.getServerSlogan());
  1807. cv.put(ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION, capability.getEndToEndEncryption().getValue());
  1808. cv.put(ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_DEFAULT, capability.getServerBackgroundDefault()
  1809. .getValue());
  1810. cv.put(ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_PLAIN, capability.getServerBackgroundPlain()
  1811. .getValue());
  1812. cv.put(ProviderTableMeta.CAPABILITIES_ACTIVITY, capability.getActivity().getValue());
  1813. cv.put(ProviderTableMeta.CAPABILITIES_RICHDOCUMENT, capability.getRichDocuments().getValue());
  1814. cv.put(ProviderTableMeta.CAPABILITIES_RICHDOCUMENT_MIMETYPE_LIST,
  1815. TextUtils.join(",", capability.getRichDocumentsMimeTypeList()));
  1816. cv.put(ProviderTableMeta.CAPABILITIES_RICHDOCUMENT_OPTIONAL_MIMETYPE_LIST,
  1817. TextUtils.join(",", capability.getRichDocumentsOptionalMimeTypeList()));
  1818. cv.put(ProviderTableMeta.CAPABILITIES_RICHDOCUMENT_DIRECT_EDITING, capability.getRichDocumentsDirectEditing()
  1819. .getValue());
  1820. cv.put(ProviderTableMeta.CAPABILITIES_RICHDOCUMENT_TEMPLATES, capability.getRichDocumentsTemplatesAvailable()
  1821. .getValue());
  1822. cv.put(ProviderTableMeta.CAPABILITIES_RICHDOCUMENT_PRODUCT_NAME, capability.getRichDocumentsProductName());
  1823. return cv;
  1824. }
  1825. private boolean capabilityExists(String accountName) {
  1826. Cursor c = getCapabilityCursorForAccount(accountName);
  1827. boolean exists = false;
  1828. if (c != null) {
  1829. exists = c.moveToFirst();
  1830. c.close();
  1831. }
  1832. return exists;
  1833. }
  1834. private Cursor getCapabilityCursorForAccount(String accountName) {
  1835. Cursor c = null;
  1836. if (getContentResolver() != null) {
  1837. c = getContentResolver()
  1838. .query(ProviderTableMeta.CONTENT_URI_CAPABILITIES,
  1839. null,
  1840. ProviderTableMeta.CAPABILITIES_ACCOUNT_NAME + "=? ",
  1841. new String[]{accountName}, null);
  1842. } else {
  1843. try {
  1844. c = getContentProviderClient().query(
  1845. ProviderTableMeta.CONTENT_URI_CAPABILITIES,
  1846. null,
  1847. ProviderTableMeta.CAPABILITIES_ACCOUNT_NAME + "=? ",
  1848. new String[]{accountName}, null);
  1849. } catch (RemoteException e) {
  1850. Log_OC.e(TAG, "Couldn't determine capability existence, assuming non existance: " + e.getMessage(), e);
  1851. }
  1852. }
  1853. return c;
  1854. }
  1855. @NonNull
  1856. public OCCapability getCapability(String accountName) {
  1857. OCCapability capability;
  1858. Cursor c = getCapabilityCursorForAccount(accountName);
  1859. if (c.moveToFirst()) {
  1860. capability = createCapabilityInstance(c);
  1861. } else {
  1862. capability = new OCCapability(); // return default with all UNKNOWN
  1863. }
  1864. c.close();
  1865. return capability;
  1866. }
  1867. private OCCapability createCapabilityInstance(Cursor c) {
  1868. OCCapability capability = null;
  1869. if (c != null) {
  1870. capability = new OCCapability();
  1871. capability.setId(c.getLong(c.getColumnIndex(ProviderTableMeta._ID)));
  1872. capability.setAccountName(c.getString(c
  1873. .getColumnIndex(ProviderTableMeta.CAPABILITIES_ACCOUNT_NAME)));
  1874. capability.setVersionMayor(c.getInt(c
  1875. .getColumnIndex(ProviderTableMeta.CAPABILITIES_VERSION_MAYOR)));
  1876. capability.setVersionMinor(c.getInt(c
  1877. .getColumnIndex(ProviderTableMeta.CAPABILITIES_VERSION_MINOR)));
  1878. capability.setVersionMicro(c.getInt(c
  1879. .getColumnIndex(ProviderTableMeta.CAPABILITIES_VERSION_MICRO)));
  1880. capability.setVersionString(c.getString(c
  1881. .getColumnIndex(ProviderTableMeta.CAPABILITIES_VERSION_STRING)));
  1882. capability.setVersionEdition(c.getString(c
  1883. .getColumnIndex(ProviderTableMeta.CAPABILITIES_VERSION_EDITION)));
  1884. capability.setExtendedSupport(CapabilityBooleanType.fromValue(c.getInt(c
  1885. .getColumnIndex(ProviderTableMeta.CAPABILITIES_EXTENDED_SUPPORT))));
  1886. capability.setCorePollInterval(c.getInt(c
  1887. .getColumnIndex(ProviderTableMeta.CAPABILITIES_CORE_POLLINTERVAL)));
  1888. capability.setFilesSharingApiEnabled(CapabilityBooleanType.fromValue(c.getInt(c
  1889. .getColumnIndex(ProviderTableMeta.CAPABILITIES_SHARING_API_ENABLED))));
  1890. capability.setFilesSharingPublicEnabled(CapabilityBooleanType.fromValue(c.getInt(c
  1891. .getColumnIndex(ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_ENABLED))));
  1892. capability.setFilesSharingPublicPasswordEnforced(CapabilityBooleanType.fromValue(c.getInt(c
  1893. .getColumnIndex(ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_PASSWORD_ENFORCED))));
  1894. capability.setFilesSharingPublicAskForOptionalPassword(
  1895. CapabilityBooleanType.fromValue(
  1896. c.getInt(c.getColumnIndex(ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_ASK_FOR_OPTIONAL_PASSWORD))));
  1897. capability.setFilesSharingPublicExpireDateEnabled(CapabilityBooleanType.fromValue(c.getInt(c
  1898. .getColumnIndex(ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_EXPIRE_DATE_ENABLED))));
  1899. capability.setFilesSharingPublicExpireDateDays(c.getInt(c
  1900. .getColumnIndex(ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_EXPIRE_DATE_DAYS)));
  1901. capability.setFilesSharingPublicExpireDateEnforced(CapabilityBooleanType.fromValue(c.getInt(c
  1902. .getColumnIndex(ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_EXPIRE_DATE_ENFORCED))));
  1903. capability.setFilesSharingPublicSendMail(CapabilityBooleanType.fromValue(c.getInt(c
  1904. .getColumnIndex(ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_SEND_MAIL))));
  1905. capability.setFilesSharingPublicUpload(CapabilityBooleanType.fromValue(c.getInt(c
  1906. .getColumnIndex(ProviderTableMeta.CAPABILITIES_SHARING_PUBLIC_UPLOAD))));
  1907. capability.setFilesSharingUserSendMail(CapabilityBooleanType.fromValue(c.getInt(c
  1908. .getColumnIndex(ProviderTableMeta.CAPABILITIES_SHARING_USER_SEND_MAIL))));
  1909. capability.setFilesSharingResharing(CapabilityBooleanType.fromValue(c.getInt(c
  1910. .getColumnIndex(ProviderTableMeta.CAPABILITIES_SHARING_RESHARING))));
  1911. capability.setFilesSharingFederationOutgoing(CapabilityBooleanType.fromValue(c.getInt(c
  1912. .getColumnIndex(ProviderTableMeta.CAPABILITIES_SHARING_FEDERATION_OUTGOING))));
  1913. capability.setFilesSharingFederationIncoming(CapabilityBooleanType.fromValue(c.getInt(c
  1914. .getColumnIndex(ProviderTableMeta.CAPABILITIES_SHARING_FEDERATION_INCOMING))));
  1915. capability.setFilesBigFileChunking(CapabilityBooleanType.fromValue(c.getInt(c
  1916. .getColumnIndex(ProviderTableMeta.CAPABILITIES_FILES_BIGFILECHUNKING))));
  1917. capability.setFilesUndelete(CapabilityBooleanType.fromValue(c.getInt(c
  1918. .getColumnIndex(ProviderTableMeta.CAPABILITIES_FILES_UNDELETE))));
  1919. capability.setFilesVersioning(CapabilityBooleanType.fromValue(c.getInt(c
  1920. .getColumnIndex(ProviderTableMeta.CAPABILITIES_FILES_VERSIONING))));
  1921. capability.setFilesFileDrop(CapabilityBooleanType.fromValue(c.getInt(c
  1922. .getColumnIndex(ProviderTableMeta.CAPABILITIES_FILES_DROP))));
  1923. capability.setExternalLinks(CapabilityBooleanType.fromValue(c.getInt(c
  1924. .getColumnIndex(ProviderTableMeta.CAPABILITIES_EXTERNAL_LINKS))));
  1925. capability.setServerName(c.getString(c.getColumnIndex(ProviderTableMeta.CAPABILITIES_SERVER_NAME)));
  1926. capability.setServerColor(c.getString(c.getColumnIndex(ProviderTableMeta.CAPABILITIES_SERVER_COLOR)));
  1927. capability.setServerTextColor(
  1928. c.getString(c.getColumnIndex(ProviderTableMeta.CAPABILITIES_SERVER_TEXT_COLOR)));
  1929. capability.setServerElementColor(
  1930. c.getString(c.getColumnIndex(ProviderTableMeta.CAPABILITIES_SERVER_ELEMENT_COLOR)));
  1931. capability.setServerBackground(c.getString(c.getColumnIndex(
  1932. ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_URL)));
  1933. capability.setServerSlogan(c.getString(c.getColumnIndex(ProviderTableMeta.CAPABILITIES_SERVER_SLOGAN)));
  1934. capability.setEndToEndEncryption(CapabilityBooleanType.fromValue(c.getInt(c
  1935. .getColumnIndex(ProviderTableMeta.CAPABILITIES_END_TO_END_ENCRYPTION))));
  1936. capability.setServerBackgroundDefault(CapabilityBooleanType.fromValue(
  1937. c.getInt(c.getColumnIndex(ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_DEFAULT))));
  1938. capability.setServerBackgroundPlain(CapabilityBooleanType.fromValue(
  1939. c.getInt(c.getColumnIndex(ProviderTableMeta.CAPABILITIES_SERVER_BACKGROUND_PLAIN))));
  1940. capability.setActivity(CapabilityBooleanType.fromValue(
  1941. c.getInt(c.getColumnIndex(ProviderTableMeta.CAPABILITIES_ACTIVITY))));
  1942. capability.setRichDocuments(CapabilityBooleanType.fromValue(c.getInt(
  1943. c.getColumnIndex(ProviderTableMeta.CAPABILITIES_RICHDOCUMENT))));
  1944. capability.setRichDocumentsDirectEditing(CapabilityBooleanType.fromValue(c.getInt(
  1945. c.getColumnIndex(ProviderTableMeta.CAPABILITIES_RICHDOCUMENT_DIRECT_EDITING))));
  1946. capability.setRichDocumentsTemplatesAvailable(CapabilityBooleanType.fromValue(c.getInt(
  1947. c.getColumnIndex(ProviderTableMeta.CAPABILITIES_RICHDOCUMENT_TEMPLATES))));
  1948. String mimetypes = c.getString(c.getColumnIndex(ProviderTableMeta.CAPABILITIES_RICHDOCUMENT_MIMETYPE_LIST));
  1949. if (mimetypes == null) {
  1950. mimetypes = "";
  1951. }
  1952. capability.setRichDocumentsMimeTypeList(Arrays.asList(mimetypes.split(",")));
  1953. String optionalMimetypes = c.getString(c.getColumnIndex(
  1954. ProviderTableMeta.CAPABILITIES_RICHDOCUMENT_OPTIONAL_MIMETYPE_LIST));
  1955. if (optionalMimetypes == null) {
  1956. optionalMimetypes = "";
  1957. }
  1958. capability.setRichDocumentsOptionalMimeTypeList(Arrays.asList(optionalMimetypes.split(",")));
  1959. capability.setRichDocumentsProductName(
  1960. c.getString(c.getColumnIndex(ProviderTableMeta.CAPABILITIES_RICHDOCUMENT_PRODUCT_NAME)));
  1961. }
  1962. return capability;
  1963. }
  1964. public void deleteVirtuals(VirtualFolderType type) {
  1965. if (getContentResolver() != null) {
  1966. getContentResolver().delete(ProviderTableMeta.CONTENT_URI_VIRTUAL,
  1967. ProviderTableMeta.VIRTUAL_TYPE + "=?", new String[]{String.valueOf(type)});
  1968. } else {
  1969. try {
  1970. getContentProviderClient().delete(ProviderTableMeta.CONTENT_URI_VIRTUAL,
  1971. ProviderTableMeta.VIRTUAL_TYPE + "=?", new String[]{String.valueOf(type)});
  1972. } catch (RemoteException e) {
  1973. Log_OC.e(TAG, FAILED_TO_INSERT_MSG + e.getMessage(), e);
  1974. }
  1975. }
  1976. }
  1977. public void saveVirtuals(VirtualFolderType type, List<ContentValues> values) {
  1978. if (getContentResolver() != null) {
  1979. getContentResolver().bulkInsert(ProviderTableMeta.CONTENT_URI_VIRTUAL, values.toArray(new ContentValues[0]));
  1980. } else {
  1981. try {
  1982. getContentProviderClient().bulkInsert(ProviderTableMeta.CONTENT_URI_VIRTUAL, values.toArray(new ContentValues[0]));
  1983. } catch (RemoteException e) {
  1984. Log_OC.e(TAG, FAILED_TO_INSERT_MSG + e.getMessage(), e);
  1985. }
  1986. }
  1987. }
  1988. public void saveVirtual(VirtualFolderType type, OCFile file) {
  1989. ContentValues cv = new ContentValues();
  1990. cv.put(ProviderTableMeta.VIRTUAL_TYPE, type.toString());
  1991. cv.put(ProviderTableMeta.VIRTUAL_OCFILE_ID, file.getFileId());
  1992. if (getContentResolver() != null) {
  1993. getContentResolver().insert(ProviderTableMeta.CONTENT_URI_VIRTUAL, cv);
  1994. } else {
  1995. try {
  1996. getContentProviderClient().insert(ProviderTableMeta.CONTENT_URI_VIRTUAL, cv);
  1997. } catch (RemoteException e) {
  1998. Log_OC.e(TAG, FAILED_TO_INSERT_MSG + e.getMessage(), e);
  1999. }
  2000. }
  2001. }
  2002. public List<OCFile> getVirtualFolderContent(VirtualFolderType type, boolean onlyImages) {
  2003. List<OCFile> ocFiles = new ArrayList<>();
  2004. Uri req_uri = ProviderTableMeta.CONTENT_URI_VIRTUAL;
  2005. Cursor c;
  2006. if (getContentProviderClient() != null) {
  2007. try {
  2008. c = getContentProviderClient().query(
  2009. req_uri,
  2010. null,
  2011. ProviderTableMeta.VIRTUAL_TYPE + "=?",
  2012. new String[]{String.valueOf(type)},
  2013. null
  2014. );
  2015. } catch (RemoteException e) {
  2016. Log_OC.e(TAG, e.getMessage(), e);
  2017. return ocFiles;
  2018. }
  2019. } else {
  2020. c = getContentResolver().query(
  2021. req_uri,
  2022. null,
  2023. ProviderTableMeta.VIRTUAL_TYPE + "=?",
  2024. new String[]{String.valueOf(type)},
  2025. null
  2026. );
  2027. }
  2028. if (c != null) {
  2029. if (c.moveToFirst()) {
  2030. do {
  2031. OCFile child = createFileInstanceFromVirtual(c);
  2032. if (child != null) {
  2033. ocFiles.add(child);
  2034. }
  2035. } while (c.moveToNext());
  2036. }
  2037. c.close();
  2038. }
  2039. if (onlyImages) {
  2040. List<OCFile> temp = new ArrayList<>();
  2041. for (OCFile file : ocFiles) {
  2042. if (MimeTypeUtil.isImage(file)) {
  2043. temp.add(file);
  2044. }
  2045. }
  2046. ocFiles = temp;
  2047. }
  2048. if (ocFiles.size() > 0) {
  2049. Collections.sort(ocFiles);
  2050. }
  2051. return ocFiles;
  2052. }
  2053. public void deleteAllFiles() {
  2054. String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "= ? AND " +
  2055. ProviderTableMeta.FILE_PATH + "= ?";
  2056. String[] whereArgs = new String[]{account.name, OCFile.ROOT_PATH};
  2057. if (getContentResolver() != null) {
  2058. getContentResolver().delete(ProviderTableMeta.CONTENT_URI_DIR, where, whereArgs);
  2059. } else {
  2060. try {
  2061. getContentProviderClient().delete(ProviderTableMeta.CONTENT_URI_DIR, where, whereArgs);
  2062. } catch (RemoteException e) {
  2063. Log_OC.e(TAG, "Exception in deleteAllFiles for account " + account.name + ": " + e.getMessage(), e);
  2064. }
  2065. }
  2066. }
  2067. }