diff --git a/app/build.gradle b/app/build.gradle index 8d11cf62a2a85ce17645936d189777f791768145..db4f90bce14b0ac797d3da286eb0abd0e9352a4e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,7 +5,7 @@ plugins { def versionMajor = 1 def versionMinor = 2 -def versionPatch = 2 +def versionPatch = 3 diff --git a/app/src/main/java/foundation/e/drive/database/DbHelper.java b/app/src/main/java/foundation/e/drive/database/DbHelper.java index 77a584215841ca7b7989086be17cfbbb4f34ca0e..c0d2d9cb5b063f4a1d172552ddb4f289f84c1d1c 100644 --- a/app/src/main/java/foundation/e/drive/database/DbHelper.java +++ b/app/src/main/java/foundation/e/drive/database/DbHelper.java @@ -298,6 +298,41 @@ public final class DbHelper extends SQLiteOpenHelper { return result; } + /** + * Look if there is some known file that need to be uploaded for the given syncedFolder + * @param syncedFolderID id of the syncedFolder + * @param context context + * @return true if there is at least one file that need to be uploaded + */ + public static boolean syncedFolderHasContentToUpload(long syncedFolderID, Context context) { + boolean result = false; + try { + final SyncedFileStateDAO dao = openSyncedFileStateDAO(context, false); + result = dao.countFileWaitingForUploadForSyncedFolder(syncedFolderID) > 0; + dao.close(); + } catch (SQLiteException e) { + Log.e(TAG, "SQlite error", e); + } + return result; + } + + /** + * Look if there us some known file that need to be downloaded for the given syncedFolder + * @param syncedFolderId SyncedFolderId + * @param context context + * @return true if there is at least one file to download + */ + public static boolean syncedFolderHasContentToDownload(int syncedFolderId, Context context) { + boolean result = false; + try { + final SyncedFileStateDAO dao = openSyncedFileStateDAO(context, false); + result = dao.countFileWaitingForDownloadForSyncedFolder(syncedFolderId) > 0; + dao.close(); + } catch (SQLiteException e) { + Log.e(TAG, "SQLite error", e); + } + return result; + } /** * Copy database file into user accessible directory for debuging purpose diff --git a/app/src/main/java/foundation/e/drive/database/SyncedFileStateDAO.java b/app/src/main/java/foundation/e/drive/database/SyncedFileStateDAO.java index fffc4da0d4163e0f65060d3bcb0d4f81959e1318..9f93de59c7e9eb0f2ca0abd4a06e37792fd0b770 100644 --- a/app/src/main/java/foundation/e/drive/database/SyncedFileStateDAO.java +++ b/app/src/main/java/foundation/e/drive/database/SyncedFileStateDAO.java @@ -15,6 +15,8 @@ import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteDoneException; +import android.database.sqlite.SQLiteStatement; import android.util.Log; import java.util.ArrayList; @@ -140,12 +142,50 @@ class SyncedFileStateDAO { return result; } + + /** + * Count number of SyncedFileState's entry with an empty eTAG for the given syncedFolder. + * ONLY list file that can be scan on device side + * @param syncedFolderId ID of the given synced folder + * @return number of file waiting to be uploaded + * @throws SQLiteDoneException SQL return 0 rows + */ + long countFileWaitingForUploadForSyncedFolder(long syncedFolderId) throws SQLiteDoneException { + final String query = "SELECT COUNT(*) FROM " + + TABLE_NAME + + " WHERE " + SCANNABLE + " >= 2" + + " AND " + LAST_ETAG + " = \"\"" + + " AND " + SYNCEDFOLDER_ID + " = "+syncedFolderId; + + final SQLiteStatement statement = mDB.compileStatement(query); + return statement.simpleQueryForLong(); + } + + /** + * Count number of syncedFileState's entry with an eTag but no value for local last modified + * Only file that can be scan on cloud are listed + * @param syncedFolderId The id of the syncedFolder + * @return number of file waiting to be downloaded + * @throws SQLiteDoneException SQL return 0 rows + */ + long countFileWaitingForDownloadForSyncedFolder(int syncedFolderId) throws SQLiteDoneException{ + final String query = "SELECT COUNT(*) FROM " + + TABLE_NAME + + " WHERE " + SCANNABLE + " IN (1,3)" + + " AND " + LOCAL_LAST_MODIFIED + " = 0" + + " AND length(" + LAST_ETAG + ") > 0" + + " AND " + SYNCEDFOLDER_ID + " = "+syncedFolderId; + + final SQLiteStatement statement = mDB.compileStatement(query); + return statement.simpleQueryForLong(); + } + /** - * Fetch many SyncedFileState by its localPath - * @param syncedFolderids List of path to filter. Need to be directory path + * Fetch many SyncedFileState by their syncedFolder's id + * @param syncedFolderIds List of id of parent syncedFolder. * @return List List of SyncedFileState filtered on syncedFolder ID. */ - List getBySyncedFolderID(List syncedFolderids) { + List getBySyncedFolderID(List syncedFolderIds) { String query = "Select " +SyncedFileStateContract._ID+", " +FILE_NAME+", " @@ -158,11 +198,11 @@ class SyncedFileStateDAO { + SCANNABLE +" FROM " +TABLE_NAME; - if (syncedFolderids.size() > 0) { + if (syncedFolderIds.size() > 0) { query+=" WHERE "; - for (int i = -1, idsSize = syncedFolderids.size(); ++i < idsSize; ) { - query += SYNCEDFOLDER_ID + " = " + syncedFolderids.get(i); + for (int i = -1, idsSize = syncedFolderIds.size(); ++i < idsSize; ) { + query += SYNCEDFOLDER_ID + " = " + syncedFolderIds.get(i); if (i < idsSize - 1) { query += " OR "; } @@ -233,4 +273,4 @@ class SyncedFileStateDAO { cursor.getInt(8) //scannable ); } -} +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/drive/operations/ListFileRemoteOperation.java b/app/src/main/java/foundation/e/drive/operations/ListFileRemoteOperation.java index e1e139db545f658f4e496b27c9ef4d4aaa5d3d4c..4867176e62f7fedf82ac858757a93976924d3c4b 100644 --- a/app/src/main/java/foundation/e/drive/operations/ListFileRemoteOperation.java +++ b/app/src/main/java/foundation/e/drive/operations/ListFileRemoteOperation.java @@ -113,7 +113,8 @@ public class ListFileRemoteOperation extends RemoteOperation fileList = new ArrayList<>(); - List folderIdList= new ArrayList<>(); + final List fileList = new ArrayList<>(); + final List folderIdList= new ArrayList<>(); boolean contentToSyncFound = false; - //Regenere list of application's package - if (CommonUtils.isSettingsSyncEnabled(mAccount)) generateAppListFile(); - + if (CommonUtils.isSettingsSyncEnabled(mAccount)) generateAppListFile(); final ListIterator iterator = mSyncedFolders.listIterator() ; - //Loop through folders + while(iterator.hasNext()) { final SyncedFolder syncedFolder = iterator.next(); Log.d(TAG, "SyncedFolder :"+syncedFolder.getLibelle()+", "+syncedFolder.getLocalFolder()+", "+syncedFolder.getLastModified()+", "+syncedFolder.isScanLocal()+", "+syncedFolder.getId() ); //Check it's not a hidden file - String fileName = CommonUtils.getFileNameFromPath(syncedFolder.getLocalFolder()); - if (fileName == null) { - Log.e(TAG, "getFileNameFromPath() returned null. Returning to prevent a NPE"); - return; - } - - if (syncedFolder.isMediaType() && fileName.startsWith(".")){ - iterator.remove(); - continue; - } - - //Check it can be scann from local - if (!syncedFolder.isScanLocal()){ + final String fileName = CommonUtils.getFileNameFromPath(syncedFolder.getLocalFolder()); + if (fileName == null || fileName.startsWith(".") || !syncedFolder.isScanLocal()) { iterator.remove(); continue; } - //Check if it's a new folder - if ( syncedFolder.getId() == -1) { - Log.v(TAG, "This is a new folder, we must register it"); - //persist new syncedFolder - int syncedFolder_id = (int) DbHelper.insertSyncedFolder(syncedFolder, this); //It will return -1 if there is an error, like an already existing folder with same value - if (syncedFolder_id > 0) { - Log.v(TAG, "Folder has been registered in DB"); - syncedFolder.setId(syncedFolder_id); - } else { - Log.w(TAG, "syncedFolder " + syncedFolder.getLocalFolder() + " remove iterator because it hasn't been registered in DB or already stored"); + if (syncedFolder.getId() == -1) { + final int syncedFolder_id = (int) DbHelper.insertSyncedFolder(syncedFolder, this); //It will return -1 if there is an error, like an already existing folder with same value + if (syncedFolder_id <= 0) { iterator.remove(); continue; } + syncedFolder.setId(syncedFolder_id); } - //Get local folder corresponding - File localFolder = new File(syncedFolder.getLocalFolder()); //Obtention du fichier local - Log.d(TAG, "Local Folder (last modified / exists): "+localFolder.lastModified()+", "+localFolder.exists() ); - //Check if local folder exists - if (!localFolder.exists()){ - Log.v(TAG, "local folder doesn't exist anymore . So content has change"); + + final File localDirectory = new File(syncedFolder.getLocalFolder()); //Obtention du fichier local + Log.d(TAG, "Local Folder (last modified / exists): "+localDirectory.lastModified()+", "+localDirectory.exists() ); + + if (!localDirectory.exists()) { contentToSyncFound = true; folderIdList.add( (long) syncedFolder.getId() ); continue; } - boolean folderHasChange = false; //consider by default that file hadn't change - - //Check if folder had change - if (localFolder.lastModified() > syncedFolder.getLastModified() ) { //compare last modified date - Log.v(TAG, "local folder has changed"); - syncedFolder.setLastModified( localFolder.lastModified() ); //@Todo: it would be better to set it after all it's content has been synced - contentToSyncFound = true; //at least one dir has changed - folderHasChange = true; //The folder has change - folderIdList.add( (long) syncedFolder.getId() ); //add id into list of modified folder + if (localDirectory.lastModified() > syncedFolder.getLastModified() + || DbHelper.syncedFolderHasContentToUpload(syncedFolder.getId(), getApplicationContext())) { + syncedFolder.setLastModified(localDirectory.lastModified()); //@Todo: it would be better to set it after all it's content has been synced + contentToSyncFound = true; + folderIdList.add((long) syncedFolder.getId()); } - //Get sub files + final FileFilter filter = FileFilterFactory.getFileFilter( (syncedFolder.isMediaType()) ? "media" : syncedFolder.getLibelle() ); - File[] subElements = localFolder.listFiles(filter); //hiden media files are being ignored - - Log.v(TAG, "loop through subfiles"); - for (int i = -1, subEltSize = (subElements != null)? subElements.length: 0; ++i < subEltSize; ) { - File subElt = subElements[i]; - if (subElt == null) continue; - if (subElt.isDirectory()) { //if its a subfolder add it to syncedFolder list - //if a subfolder is found, add it to syncedFolder list - Log.v(TAG, "subfile "+subElt.getAbsolutePath()+" is a directory."); - SyncedFolder subSyncedFolder = new SyncedFolder(syncedFolder, subElt.getName() + FileUtils.PATH_SEPARATOR, 0L, "");//Need to put 0 into to be handled on next iterati + final File[] subFiles = localDirectory.listFiles(filter); //skip hidden media files + + if (subFiles == null) continue; + for (File subFile : subFiles) { + if (subFile.isDirectory()) { + final SyncedFolder subSyncedFolder = new SyncedFolder(syncedFolder, subFile.getName() + FileUtils.PATH_SEPARATOR, 0L, "");//Need to set lastModified to 0 to handle it on next iteration iterator.add(subSyncedFolder); iterator.previous(); - - } else { - if (folderHasChange) { //only consider files if folder had change - Log.v(TAG, "subfile " + subElt.getAbsolutePath() + " is a file added to list of file to sync"); - fileList.add(subElt); - } + } else if (contentToSyncFound) { + Log.v(TAG, "added subfile " + subFile.getAbsolutePath() + " into list of file to sync"); + fileList.add(subFile); } } - } //end of iterator loop + } + if (contentToSyncFound) { DbHelper.updateSyncedFolders(mSyncedFolders, this); //@ToDo: maybe do this when all contents will be synced. - List syncedFileStates = DbHelper.getSyncedFileStatesByFolders(this, + final List syncedFileStates = DbHelper.getSyncedFileStatesByFolders(this, folderIdList); if (!syncedFileStates.isEmpty() || !fileList.isEmpty() ) { diff --git a/app/src/main/java/foundation/e/drive/utils/FileDiffUtils.java b/app/src/main/java/foundation/e/drive/utils/FileDiffUtils.java index 2880ec2ab1661dc9d083c8e395275c8948fe1bac..3e9410fefe819e42eda70111d630f6d84acc2370 100644 --- a/app/src/main/java/foundation/e/drive/utils/FileDiffUtils.java +++ b/app/src/main/java/foundation/e/drive/utils/FileDiffUtils.java @@ -43,7 +43,6 @@ public class FileDiffUtils { if (isRemoteSizeSameAsLocalSize(remoteFile, localFile)) { return Action.updateDB; } - return Action.Download; } @@ -80,7 +79,7 @@ public class FileDiffUtils { * @return true if localLastModified store in Database == 0 */ private static boolean hasAlreadyBeenDownloaded(SyncedFileState fileState) { - return fileState.getLocalLastModified() == 0L; + return fileState.getLocalLastModified() > 0L; } /**