diff --git a/services_app/src/androidTest/java/org/opendatakit/services/sync/service/logic/AggregateSynchronizerTest.java b/services_app/src/androidTest/java/org/opendatakit/services/sync/service/logic/AggregateSynchronizerTest.java index 7c3f561c5..603e4a8b4 100644 --- a/services_app/src/androidTest/java/org/opendatakit/services/sync/service/logic/AggregateSynchronizerTest.java +++ b/services_app/src/androidTest/java/org/opendatakit/services/sync/service/logic/AggregateSynchronizerTest.java @@ -1375,7 +1375,7 @@ public void testDownloadBatch_ExpectPass() { synchronizer.uploadInstanceFile(destFile2, cat2.instanceFileDownloadUri); synchronizer.downloadInstanceFileBatch(listOfCats, testTableRes.getInstanceFilesUri(), - rowId, testTableId); + rowId, testTableId, false); synchronizer.deleteTable(testTableRes); diff --git a/services_app/src/main/java/org/opendatakit/services/sync/service/AppSynchronizer.java b/services_app/src/main/java/org/opendatakit/services/sync/service/AppSynchronizer.java index 297dba691..a6946fa5e 100644 --- a/services_app/src/main/java/org/opendatakit/services/sync/service/AppSynchronizer.java +++ b/services_app/src/main/java/org/opendatakit/services/sync/service/AppSynchronizer.java @@ -20,6 +20,8 @@ import org.opendatakit.aggregate.odktables.rest.entity.TableResource; import org.opendatakit.exception.ServicesAvailabilityException; import org.opendatakit.logging.WebLogger; +import org.opendatakit.properties.CommonToolProperties; +import org.opendatakit.properties.PropertiesSingleton; import org.opendatakit.services.R; import org.opendatakit.services.sync.service.exceptions.AccessDeniedException; import org.opendatakit.services.sync.service.exceptions.NoAppNameSpecifiedException; @@ -37,6 +39,7 @@ import org.opendatakit.sync.service.TableLevelResult; import org.opendatakit.utilities.ODKFileUtils; +import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -163,6 +166,7 @@ private class SyncTask implements Runnable { private final boolean onlyVerifySettings; private final boolean push; private final SyncAttachmentState attachmentState; + private PropertiesSingleton properties; public SyncTask(Context context, String versionCodeString) { this.context = context; @@ -170,6 +174,7 @@ public SyncTask(Context context, String versionCodeString) { this.onlyVerifySettings = true; this.push = false; this.attachmentState = SyncAttachmentState.NONE; + this.properties = CommonToolProperties.get(context, appName); } public SyncTask(Context context, String versionCodeString, boolean push, SyncAttachmentState attachmentState) { @@ -178,6 +183,7 @@ public SyncTask(Context context, String versionCodeString, boolean push, SyncAtt this.onlyVerifySettings = false; this.push = push; this.attachmentState = attachmentState; + this.properties = CommonToolProperties.get(context, appName); } @Override @@ -316,8 +322,13 @@ private void sync() { // was an app-level sync failure or if the particular tableId // experienced a table-level sync failure in the preceeding step. + String prevDownloadAttachmentStateStr = properties.getProperty(CommonToolProperties.KEY_PREV_SYNC_ATTACHMENT_STATE); + SyncAttachmentState prevDownloadAttachmentState = SyncAttachmentState.valueOf(prevDownloadAttachmentStateStr); try { - rowDataProcessor.synchronizeDataRowsAndAttachments(workingListOfTables, attachmentState); + rowDataProcessor.synchronizeDataRowsAndAttachments(workingListOfTables, attachmentState, prevDownloadAttachmentState); + if (SyncAttachmentState.involvesDownload(attachmentState)) { + properties.setProperties(Collections.singletonMap(CommonToolProperties.KEY_PREV_SYNC_ATTACHMENT_STATE, attachmentState.name())); + } } catch (ServicesAvailabilityException e) { WebLogger.getLogger(appName).printStackTrace(e); } finally { diff --git a/services_app/src/main/java/org/opendatakit/services/sync/service/logic/AggregateSynchronizer.java b/services_app/src/main/java/org/opendatakit/services/sync/service/logic/AggregateSynchronizer.java index e5a82d415..284ca420d 100644 --- a/services_app/src/main/java/org/opendatakit/services/sync/service/logic/AggregateSynchronizer.java +++ b/services_app/src/main/java/org/opendatakit/services/sync/service/logic/AggregateSynchronizer.java @@ -1052,7 +1052,7 @@ public void uploadInstanceFileBatch(List batch, @Override public void downloadInstanceFileBatch(List filesToDownload, - String serverInstanceFileUri, String instanceId, String tableId) throws HttpClientWebException, IOException { + String serverInstanceFileUri, String instanceId, String tableId, boolean reduceImageSize) throws HttpClientWebException, IOException { // boolean downloadedAllFiles = true; URI instanceFilesDownloadUri = wrapper.constructInstanceFileBulkDownloadUri(serverInstanceFileUri, instanceId); @@ -1061,6 +1061,7 @@ public void downloadInstanceFileBatch(List filesToDow for (CommonFileAttachmentTerms cat : filesToDownload) { OdkTablesFileManifestEntry entry = new OdkTablesFileManifestEntry(); entry.filename = cat.rowPathUri; + entry.reduceImage = String.valueOf(reduceImageSize); entries.add(entry); } diff --git a/services_app/src/main/java/org/opendatakit/services/sync/service/logic/AidlSynchronizer.java b/services_app/src/main/java/org/opendatakit/services/sync/service/logic/AidlSynchronizer.java index 57b9f3217..c2a6c9a5d 100644 --- a/services_app/src/main/java/org/opendatakit/services/sync/service/logic/AidlSynchronizer.java +++ b/services_app/src/main/java/org/opendatakit/services/sync/service/logic/AidlSynchronizer.java @@ -337,9 +337,9 @@ public void uploadInstanceFileBatch(List batch, Strin } @Override - public void downloadInstanceFileBatch(List filesToDownload, String serverInstanceFileUri, String instanceId, String tableId) throws HttpClientWebException { + public void downloadInstanceFileBatch(List filesToDownload, String serverInstanceFileUri, String instanceId, String tableId, boolean reduceImageSize) throws HttpClientWebException { try { - getRemoteInterface().downloadInstanceFileBatch(filesToDownload, serverInstanceFileUri, instanceId, tableId); + getRemoteInterface().downloadInstanceFileBatch(filesToDownload, serverInstanceFileUri, instanceId, tableId, reduceImageSize); } catch (RemoteException e) { rethrowException(e); } diff --git a/services_app/src/main/java/org/opendatakit/services/sync/service/logic/HttpSynchronizer.java b/services_app/src/main/java/org/opendatakit/services/sync/service/logic/HttpSynchronizer.java index 362bf6720..597891ddd 100644 --- a/services_app/src/main/java/org/opendatakit/services/sync/service/logic/HttpSynchronizer.java +++ b/services_app/src/main/java/org/opendatakit/services/sync/service/logic/HttpSynchronizer.java @@ -368,7 +368,7 @@ void uploadInstanceFileBatch(List batch, String serve */ @Override void downloadInstanceFileBatch(List filesToDownload, - String serverInstanceFileUri, String instanceId, String tableId) + String serverInstanceFileUri, String instanceId, String tableId, boolean reduceImageSize) throws HttpClientWebException, IOException; /** diff --git a/services_app/src/main/java/org/opendatakit/services/sync/service/logic/ProcessManifestContentAndFileChanges.java b/services_app/src/main/java/org/opendatakit/services/sync/service/logic/ProcessManifestContentAndFileChanges.java index 37dd388ef..6ab1a609a 100644 --- a/services_app/src/main/java/org/opendatakit/services/sync/service/logic/ProcessManifestContentAndFileChanges.java +++ b/services_app/src/main/java/org/opendatakit/services/sync/service/logic/ProcessManifestContentAndFileChanges.java @@ -703,7 +703,7 @@ private boolean compareAndDownloadConfigFile(String tableId, OdkTablesFileManife * the server. Based upon that and the attachmentState actions, it determines * whether the row can be transitioned into the synced state (from synced_pending_files). * - * @param serverInstanceFileUri + * @param serverInstanceFileUri Note that this does not identify a file on a server * @param tableId * @param localRow * @param attachmentState @@ -816,7 +816,12 @@ public boolean syncRowLevelFileAttachments(String serverInstanceFileUri, String // Check if the server and local versions match String localMd5 = ODKFileUtils.getMd5Hash(sc.getAppName(), cat.localFile); - if (!localMd5.equals(entry.md5hash)) { + if (attachmentState == SyncAttachmentState.REDUCED_DOWNLOAD + || attachmentState == SyncAttachmentState.SYNC_WITH_REDUCED_DOWNLOAD) { + if (!(localMd5.equals(entry.md5hash) || localMd5.equals(entry.reducedImageMd5Hash))) { + filesToDownloadSizes.put(cat, entry.contentLength); + } + } else if (!localMd5.equals(entry.md5hash)) { // Found, but it is wrong locally, so we need to pull it log.e(LOGTAG, "syncRowLevelFileAttachments Row-level Manifest: md5Hash on server does not match local file hash!"); filesToDownloadSizes.put(cat, entry.contentLength); @@ -868,6 +873,7 @@ public boolean syncRowLevelFileAttachments(String serverInstanceFileUri, String log.i(LOGTAG, "syncRowLevelFileAttachments no files to send to server -- they are all synced"); fullySyncedUploads = true; } else if (attachmentState.equals(SyncAttachmentState.SYNC) || + attachmentState.equals(SyncAttachmentState.SYNC_WITH_REDUCED_DOWNLOAD) || attachmentState.equals(SyncAttachmentState.UPLOAD)) { long batchSize = 0; List batch = new LinkedList(); @@ -899,14 +905,20 @@ public boolean syncRowLevelFileAttachments(String serverInstanceFileUri, String fullySyncedUploads = true; } // 5) Download the files from the server + boolean atleast1Download = false; if (filesToDownloadSizes.isEmpty()){ log.i(LOGTAG, "syncRowLevelFileAttachments no files to fetch from server -- they are all synced"); fullySyncedDownloads = !impossibleToFullySyncDownloadsServerMissingFileToDownload; } else if (attachmentState.equals(SyncAttachmentState.SYNC) || - attachmentState.equals(SyncAttachmentState.DOWNLOAD)) { + attachmentState.equals(SyncAttachmentState.SYNC_WITH_REDUCED_DOWNLOAD) || + attachmentState.equals(SyncAttachmentState.DOWNLOAD) || + attachmentState.equals(SyncAttachmentState.REDUCED_DOWNLOAD)) { + atleast1Download = true; long batchSize = 0; List batch = new LinkedList(); + boolean reduceImageSize = attachmentState == SyncAttachmentState.REDUCED_DOWNLOAD || + attachmentState == SyncAttachmentState.SYNC_WITH_REDUCED_DOWNLOAD; for (CommonFileAttachmentTerms fileAttachment : filesToDownloadSizes.keySet()) { // Check if adding the file exceeds the batch limit. If so, download the current batch @@ -917,7 +929,7 @@ public boolean syncRowLevelFileAttachments(String serverInstanceFileUri, String !batch.isEmpty()) { log.i(LOGTAG, "syncRowLevelFileAttachments downloading batch for " + instanceId); sc.getSynchronizer().downloadInstanceFileBatch(batch, - serverInstanceFileUri, instanceId, tableId); + serverInstanceFileUri, instanceId, tableId, reduceImageSize); batch.clear(); batchSize = 0; } @@ -930,14 +942,14 @@ public boolean syncRowLevelFileAttachments(String serverInstanceFileUri, String // download the final batch log.i(LOGTAG, "syncRowLevelFileAttachments downloading batch for " + instanceId); sc.getSynchronizer().downloadInstanceFileBatch(batch, serverInstanceFileUri, - instanceId, tableId); + instanceId, tableId, reduceImageSize); } fullySyncedDownloads = !impossibleToFullySyncDownloadsServerMissingFileToDownload; } if ( attachmentState == SyncAttachmentState.NONE || - ((fullySyncedUploads || (attachmentState == SyncAttachmentState.DOWNLOAD)) && + ((fullySyncedUploads || (attachmentState == SyncAttachmentState.DOWNLOAD || attachmentState == SyncAttachmentState.REDUCED_DOWNLOAD)) && (fullySyncedDownloads || (attachmentState == SyncAttachmentState.UPLOAD))) ) { // there may be synced_pending_files rows, but all of the uploads we want to do // have been uploaded, and all of the downloads we want to do have been downloaded. diff --git a/services_app/src/main/java/org/opendatakit/services/sync/service/logic/ProcessRowDataOrchestrateChanges.java b/services_app/src/main/java/org/opendatakit/services/sync/service/logic/ProcessRowDataOrchestrateChanges.java index cd77c2c9c..e64ad4c34 100644 --- a/services_app/src/main/java/org/opendatakit/services/sync/service/logic/ProcessRowDataOrchestrateChanges.java +++ b/services_app/src/main/java/org/opendatakit/services/sync/service/logic/ProcessRowDataOrchestrateChanges.java @@ -140,7 +140,7 @@ private void exception(String method, String tableId, Exception e, TableLevelRes * @throws ServicesAvailabilityException */ public void synchronizeDataRowsAndAttachments(List workingListOfTables, - SyncAttachmentState attachmentState) throws ServicesAvailabilityException { + SyncAttachmentState attachmentState, SyncAttachmentState prevAttachmentState) throws ServicesAvailabilityException { log.i(TAG, "entered synchronizeDataRowsAndAttachments()"); DbHandle db = null; @@ -167,7 +167,7 @@ public void synchronizeDataRowsAndAttachments(List workingListOfT } synchronizeTableDataRowsAndAttachments(te, orderedDefns, displayName, - attachmentState); + attachmentState, prevAttachmentState); // report our table-level sync status up to the server. TableLevelResult tlr = sc.getTableLevelResult(tableId); @@ -240,7 +240,7 @@ public void synchronizeDataRowsAndAttachments(List workingListOfT */ private void synchronizeTableDataRowsAndAttachments( TableDefinitionEntry te, OrderedColumns orderedColumns, String displayName, - SyncAttachmentState attachmentState) throws ServicesAvailabilityException { + SyncAttachmentState attachmentState, SyncAttachmentState prevAttachmentState) throws ServicesAvailabilityException { ArrayList fileAttachmentColumns = new ArrayList(); for (ColumnDefinition cd : orderedColumns.getColumnDefinitions()) { @@ -335,7 +335,7 @@ private void synchronizeTableDataRowsAndAttachments( if (!refreshFromServer) { try { syncAttachmentsProcessor - .syncAttachments(tableResource, te, orderedColumns, fileAttachmentColumns, attachmentState); + .syncAttachments(tableResource, te, orderedColumns, fileAttachmentColumns, attachmentState, prevAttachmentState); } catch (Exception e) { exception("synchronizeTableDataRowsAndAttachments - syncing attachments with server", tableId, e, tableLevelResult); diff --git a/services_app/src/main/java/org/opendatakit/services/sync/service/logic/ProcessRowDataSyncAttachments.java b/services_app/src/main/java/org/opendatakit/services/sync/service/logic/ProcessRowDataSyncAttachments.java index 6d86e39e6..38e134027 100644 --- a/services_app/src/main/java/org/opendatakit/services/sync/service/logic/ProcessRowDataSyncAttachments.java +++ b/services_app/src/main/java/org/opendatakit/services/sync/service/logic/ProcessRowDataSyncAttachments.java @@ -29,6 +29,8 @@ import org.opendatakit.database.queries.BindArgs; import org.opendatakit.database.service.DbHandle; import org.opendatakit.exception.ServicesAvailabilityException; +import org.opendatakit.properties.CommonToolProperties; +import org.opendatakit.properties.PropertiesSingleton; import org.opendatakit.provider.DataTableColumns; import org.opendatakit.services.R; import org.opendatakit.services.sync.service.SyncExecutionContext; @@ -87,7 +89,7 @@ public ProcessRowDataSyncAttachments(SyncExecutionContext sharedContext) { public void syncAttachments(TableResource tableResource, TableDefinitionEntry te, OrderedColumns orderedColumns, ArrayList fileAttachmentColumns, - SyncAttachmentState attachmentState) throws ServicesAvailabilityException { + SyncAttachmentState attachmentState, SyncAttachmentState prevAttachmentState) throws ServicesAvailabilityException { // Prepare the tableLevelResult. String tableId = te.getTableId(); @@ -137,8 +139,17 @@ public void syncAttachments(TableResource tableResource, String sqlCommand; - BindArgs bindArgs = new BindArgs(new Object[]{ SyncState.in_conflict.name(), - SyncState.synced_pending_files.name() }); + BindArgs bindArgs; + if (SyncAttachmentState.involvesReducedImgDownload(prevAttachmentState) && SyncAttachmentState.involvesFullSizeImgDownload(attachmentState)) { + // If the previous involved a reduced download and the curr involves a full download, + // we need to consider files that are in the "synced" state. + bindArgs = new BindArgs(new Object[]{ SyncState.in_conflict.name(), + SyncState.synced_pending_files.name(), SyncState.synced.name() }); + } else { + // Add synced_pending_files twice to match sql query + bindArgs = new BindArgs(new Object[]{ SyncState.in_conflict.name(), + SyncState.synced_pending_files.name(), SyncState.synced_pending_files.name() }); + } { StringBuilder sqlCommandBuilder = new StringBuilder(); @@ -146,7 +157,7 @@ public void syncAttachments(TableResource tableResource, .append(" (").append(ID_COLUMN).append(" ) SELECT DISTINCT ") .append(DataTableColumns.ID).append(" FROM ").append(tableId) .append(" WHERE ") - .append(DataTableColumns.SYNC_STATE).append(" IN (?, ?) AND ") + .append(DataTableColumns.SYNC_STATE).append(" IN (?, ?, ?) AND ") .append(DataTableColumns.ID).append(" NOT IN (SELECT DISTINCT ") .append(DataTableColumns.ID).append(" FROM ").append(tableId).append(" WHERE ") .append(DataTableColumns.SAVEPOINT_TYPE).append(" IS NULL)"); @@ -244,7 +255,9 @@ public void syncAttachments(TableResource tableResource, // anything and never update the state to synced (it must stay in in_conflict) syncAttachments = true; } - } else if (state == SyncState.synced_pending_files) { + } else if (state == SyncState.synced_pending_files || + (state == SyncState.synced && + SyncAttachmentState.involvesReducedImgDownload(prevAttachmentState) && SyncAttachmentState.involvesFullSizeImgDownload(attachmentState))) { // // if we succeed in fetching and deleting the local files to match the server // then update the state to synced. syncAttachments = true; @@ -254,7 +267,6 @@ public void syncAttachments(TableResource tableResource, // And try to push the file attachments... try { boolean outcome = true; - SyncAttachmentState filteredAttachmentState = (state == SyncState.in_conflict ? SyncAttachmentState.DOWNLOAD : attachmentState); @@ -300,12 +312,18 @@ public void syncAttachments(TableResource tableResource, case SYNC: idString = R.string.sync_syncing_attachments_server_row; break; + case SYNC_WITH_REDUCED_DOWNLOAD: + idString = R.string.sync_syncing_attachments_server_row; + break; case UPLOAD: idString = R.string.sync_uploading_attachments_server_row; break; case DOWNLOAD: idString = R.string.sync_downloading_attachments_server_row; break; + case REDUCED_DOWNLOAD: + idString = R.string.sync_downloading_attachments_server_row; + break; } publishUpdateNotification(idString, tableId); diff --git a/services_app/src/main/java/org/opendatakit/services/sync/service/logic/Synchronizer.java b/services_app/src/main/java/org/opendatakit/services/sync/service/logic/Synchronizer.java index c9a03424f..b5ed57756 100644 --- a/services_app/src/main/java/org/opendatakit/services/sync/service/logic/Synchronizer.java +++ b/services_app/src/main/java/org/opendatakit/services/sync/service/logic/Synchronizer.java @@ -389,7 +389,7 @@ void uploadInstanceFileBatch(List batch, String serve * @throws IOException */ void downloadInstanceFileBatch(List filesToDownload, - String serverInstanceFileUri, String instanceId, String tableId) + String serverInstanceFileUri, String instanceId, String tableId, boolean reduceImageSize) throws HttpClientWebException, IOException; /** diff --git a/services_app/src/main/res/values-es/arrays.xml b/services_app/src/main/res/values-es/arrays.xml index dcfacb509..a1a36746d 100644 --- a/services_app/src/main/res/values-es/arrays.xml +++ b/services_app/src/main/res/values-es/arrays.xml @@ -15,11 +15,15 @@ UPLOAD DOWNLOAD NONE + REDUCED_DOWNLOAD + SYNC_WITH_REDUCED_DOWNLOAD Sincronizar Todos Solo enviar archivos (imágenes, audio, video) al servidor Solo recibir archivos (imágenes, audio, video) del servidor No sincronizar archivos + Solo recibir archivos (imágenes (pequeño), audio, video) al servidor + Sincronizar Todos, recibir imágenes pequeño diff --git a/services_app/src/main/res/values/arrays.xml b/services_app/src/main/res/values/arrays.xml index 31021db5c..af03ea021 100644 --- a/services_app/src/main/res/values/arrays.xml +++ b/services_app/src/main/res/values/arrays.xml @@ -15,11 +15,15 @@ UPLOAD DOWNLOAD NONE + REDUCED_DOWNLOAD + SYNC_WITH_REDUCED_DOWNLOAD Fully Sync Attachments Upload Attachments Only Download Attachments Only Do Not Sync Attachments + Download Attachments Only, Reduce Img + Fully Sync Attachments, Reduce Img \ No newline at end of file