diff --git a/android/app/src/main/java/io/mosip/registration_client/MainActivity.java b/android/app/src/main/java/io/mosip/registration_client/MainActivity.java index caa82054a..27a9833b5 100644 --- a/android/app/src/main/java/io/mosip/registration_client/MainActivity.java +++ b/android/app/src/main/java/io/mosip/registration_client/MainActivity.java @@ -25,8 +25,10 @@ import com.fasterxml.jackson.databind.ObjectWriter; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -43,6 +45,7 @@ import io.mosip.registration.clientmanager.constant.Components; import io.mosip.registration.clientmanager.constant.PacketClientStatus; import io.mosip.registration.clientmanager.constant.PacketTaskStatus; +import io.mosip.registration.clientmanager.constant.RegistrationConstants; import io.mosip.registration.clientmanager.dao.GlobalParamDao; import io.mosip.registration.clientmanager.dto.CenterMachineDto; import io.mosip.registration.clientmanager.entity.GlobalParam; @@ -263,8 +266,15 @@ void scheduleAllActiveJobs() { try { List activeJobs = syncJobDefRepository.getAllSyncJobDefList(); int scheduledCount = 0; - + Set excludedJobIds = getExcludedJobIds(); for (SyncJobDef job : activeJobs) { + if (job.getId() == null) { + continue; + } + if (excludedJobIds.contains(job.getId())) { + Log.d(getClass().getSimpleName(), "Skipping excluded job: " + job.getId()); + continue; + } if (job.getIsActive() != null && job.getIsActive() && job.getApiName() != null) { Log.d(getClass().getSimpleName(), "Scheduling job: " + job.getApiName() + " (ID: " + job.getId() + ", Cron: " + job.getSyncFreq() + ")"); @@ -281,6 +291,25 @@ void scheduleAllActiveJobs() { }).start(); } + private Set getExcludedJobIds() { + Set excluded = new HashSet<>(); + addJobIdsFromString(excluded, globalParamRepository.getCachedStringJobsOffline()); + addJobIdsFromString(excluded, globalParamRepository.getCachedStringJobsUntagged()); + return excluded; + } + + private void addJobIdsFromString(Set target, String value) { + if (value == null || value.trim().isEmpty()) { + return; + } + for (String jobId : value.split(RegistrationConstants.COMMA)) { + String trimmed = jobId.trim(); + if (!trimmed.isEmpty()) { + target.add(trimmed); + } + } + } + @Override protected void onDestroy() { super.onDestroy(); @@ -386,7 +415,7 @@ public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { DynamicResponsePigeon.DynamicResponseApi.setup(flutterEngine.getDartExecutor().getBinaryMessenger(), dynamicDetailsApi); batchJob.setCallbackActivity(this); MasterDataSyncPigeon.SyncApi.setup(flutterEngine.getDartExecutor().getBinaryMessenger(), masterDataSyncApi); - masterDataSyncApi.setCallbackActivity(this, batchJob); + masterDataSyncApi.setCallbackActivity(this, batchJob, flutterEngine.getDartExecutor().getBinaryMessenger()); AuditResponsePigeon.AuditResponseApi.setup(flutterEngine.getDartExecutor().getBinaryMessenger(), auditDetailsApi); GlobalConfigSettingsPigeon.GlobalConfigSettingsApi.setup(flutterEngine.getDartExecutor().getBinaryMessenger(), globalConfigSettingsApi); SecureScreenPigeon.SecureScreenApi.setup(flutterEngine.getDartExecutor().getBinaryMessenger(), secureScreenApi); diff --git a/android/app/src/main/java/io/mosip/registration_client/api_services/MasterDataSyncApi.java b/android/app/src/main/java/io/mosip/registration_client/api_services/MasterDataSyncApi.java index 715220997..7a561b7b6 100644 --- a/android/app/src/main/java/io/mosip/registration_client/api_services/MasterDataSyncApi.java +++ b/android/app/src/main/java/io/mosip/registration_client/api_services/MasterDataSyncApi.java @@ -18,6 +18,8 @@ import android.content.Intent; import android.net.Uri; import android.os.Build; +import android.os.Handler; +import android.os.Looper; import android.os.SystemClock; import android.util.Log; import android.widget.Toast; @@ -27,7 +29,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import javax.inject.Inject; import javax.inject.Singleton; @@ -70,10 +76,13 @@ import io.mosip.registration_client.utils.BatchJob; import io.mosip.registration_client.MainActivity; import io.mosip.registration_client.UploadBackgroundService; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugin.common.MethodChannel; import io.mosip.registration_client.model.MasterDataSyncPigeon; import io.mosip.registration_client.utils.NetworkUtils; import io.mosip.registration.clientmanager.constant.AuditEvent; import io.mosip.registration.clientmanager.constant.Components; + @Singleton public class MasterDataSyncApi implements MasterDataSyncPigeon.SyncApi { private static final String MASTER_DATA_LAST_UPDATED = "masterdata.lastupdated"; @@ -110,6 +119,13 @@ public class MasterDataSyncApi implements MasterDataSyncPigeon.SyncApi { private Activity activity; BatchJob batchJob; + private BinaryMessenger flutterBinaryMessenger; + + private final Object restartLock = new Object(); + private final AtomicInteger runningSyncJobs = new AtomicInteger(0); + private final AtomicBoolean restartRequested = new AtomicBoolean(false); + private final Handler restartHandler = new Handler(Looper.getMainLooper()); + private volatile Runnable pendingRestartPrompt; @Inject public MasterDataSyncApi(ClientCryptoManagerService clientCryptoManagerService, MachineRepository machineRepository, RegistrationCenterRepository registrationCenterRepository, SyncRestService syncRestService, CertificateManagerService certificateManagerService, GlobalParamRepository globalParamRepository, ObjectMapper objectMapper, UserDetailRepository userDetailRepository, IdentitySchemaRepository identitySchemaRepository, Context context, DocumentTypeRepository documentTypeRepository, @@ -153,9 +169,10 @@ public MasterDataSyncApi(ClientCryptoManagerService clientCryptoManagerService, this.localConfigService = localConfigService; } - public void setCallbackActivity(MainActivity mainActivity, BatchJob batchJob) { + public void setCallbackActivity(MainActivity mainActivity, BatchJob batchJob, BinaryMessenger flutterBinaryMessenger) { this.activity = mainActivity; this.batchJob = batchJob; + this.flutterBinaryMessenger = flutterBinaryMessenger; } @Override @@ -174,24 +191,39 @@ public void getLastSyncTime(@NonNull MasterDataSyncPigeon.Result result) { + if (isManualSync && isExcludedJob(jobId)) { + result.success(syncResult("PolicyKeySync", 5, "")); + return; + } + onSyncJobStart(); CenterMachineDto centerMachineDto = masterDataService.getRegistrationCenterMachineDetails(); if (centerMachineDto == null) { + onSyncJobComplete(jobId, false, isManualSync); result.success(syncResult("PolicyKeySync", 5, "policy_key_sync_failed")); return; } try { masterDataService.syncCertificate(() -> { - - result.success(syncResult("PolicyKeySync", 5, masterDataService.onResponseComplete())); + String errorCode = masterDataService.onResponseComplete(); + boolean success = errorCode == null || errorCode.isEmpty(); + onSyncJobComplete(jobId, success, isManualSync); + result.success(syncResult("PolicyKeySync", 5, errorCode)); }, REG_APP_ID, centerMachineDto.getMachineRefId(), REG_APP_ID, centerMachineDto.getMachineRefId(), isManualSync, jobId); } catch (Exception e) { e.printStackTrace(); + onSyncJobComplete(jobId, false, isManualSync); } } @Override public void getGlobalParamsSync(@NonNull Boolean isManualSync, @NonNull String jobId, @NonNull MasterDataSyncPigeon.Result result) { + if (isManualSync && isExcludedJob(jobId)) { + result.success(syncResult("GlobalParamsSync", 1, "")); + return; + } + + onSyncJobStart(); try { masterDataService.syncGlobalParamsData(() -> { auditManagerService.audit( @@ -199,15 +231,24 @@ public void getGlobalParamsSync(@NonNull Boolean isManualSync, @NonNull String j Components.REGISTRATION ); Log.i(TAG, "Sync Global Params Completed."); - result.success(syncResult("GlobalParamsSync", 1, masterDataService.onResponseComplete())); + String errorCode = masterDataService.onResponseComplete(); + boolean success = errorCode == null || errorCode.isEmpty(); + onSyncJobComplete(jobId, success, isManualSync); + result.success(syncResult("GlobalParamsSync", 1, errorCode)); }, isManualSync, jobId); } catch (Exception e) { e.printStackTrace(); + onSyncJobComplete(jobId, false, isManualSync); } } @Override public void getUserDetailsSync(@NonNull Boolean isManualSync, @NonNull String jobId, @NonNull MasterDataSyncPigeon.Result result) { + if (isManualSync && isExcludedJob(jobId)) { + result.success(syncResult("UserDetailsSync", 3, "")); + return; + } + onSyncJobStart(); try { masterDataService.syncUserDetails(() -> { auditManagerService.audit( @@ -215,38 +256,61 @@ public void getUserDetailsSync(@NonNull Boolean isManualSync, @NonNull String jo Components.REGISTRATION ); Log.i(TAG, "User details sync Completed."); - result.success(syncResult("UserDetailsSync", 3, masterDataService.onResponseComplete())); + String errorCode = masterDataService.onResponseComplete(); + boolean success = errorCode == null || errorCode.isEmpty(); + onSyncJobComplete(jobId, success, isManualSync); + result.success(syncResult("UserDetailsSync", 3, errorCode)); }, isManualSync, jobId); } catch (Exception e) { e.printStackTrace(); + onSyncJobComplete(jobId, false, isManualSync); } } @Override - public void getIDSchemaSync(@NonNull Boolean isManualSync, @NonNull MasterDataSyncPigeon.Result result) { + public void getIDSchemaSync(@NonNull Boolean isManualSync, @NonNull String jobId, @NonNull MasterDataSyncPigeon.Result result) { + if (isManualSync && isExcludedJob(jobId)) { + result.success(syncResult("LatestIDSchemaSync", 4, "")); + return; + } + onSyncJobStart(); try { masterDataService.syncLatestIdSchema(() -> { Log.i(TAG, "ID Schema Sync Completed"); - result.success(syncResult("LatestIDSchemaSync", 4, masterDataService.onResponseComplete())); + String errorCode = masterDataService.onResponseComplete(); + boolean success = errorCode == null || errorCode.isEmpty(); + onSyncJobComplete(jobId, success, isManualSync); + result.success(syncResult("LatestIDSchemaSync", 4, errorCode)); }, isManualSync); } catch (Exception e) { Log.e(TAG, "ID Schema Sync Failed.", e); e.printStackTrace(); + onSyncJobComplete(jobId, false, isManualSync); + result.error(e); } } @Override public void getMasterDataSync(@NonNull Boolean isManualSync, @NonNull String jobId, @NonNull MasterDataSyncPigeon.Result result) { auditManagerService.audit(AuditEvent.NAV_SYNC_DATA, Components.REGISTRATION); + if (isManualSync && isExcludedJob(jobId)) { + result.success(syncResult("MasterDataSync", 2, "")); + return; + } + onSyncJobStart(); try { masterDataService.syncMasterData(() -> { auditManagerService.audit(AuditEvent.SYNC_MASTER_DATA,Components.REGISTRATION); Log.i(TAG, "Master Data Sync Completed."); - result.success(syncResult("MasterDataSync", 2, masterDataService.onResponseComplete())); + String errorCode = masterDataService.onResponseComplete(); + boolean success = errorCode == null || errorCode.isEmpty(); + onSyncJobComplete(jobId, success, isManualSync); + result.success(syncResult("MasterDataSync", 2, errorCode)); }, 0, isManualSync, jobId); } catch (Exception e) { Log.e(TAG, "Master Data Sync Failed.", e); e.printStackTrace(); + onSyncJobComplete(jobId, false, isManualSync); } } @@ -261,16 +325,31 @@ private MasterDataSyncPigeon.Sync syncResult(String syncType, int progress, Stri @Override public void getCaCertsSync(@NonNull Boolean isManualSync, @NonNull String jobId, @NonNull MasterDataSyncPigeon.Result result) { - masterDataService.syncCACertificates(() -> { - Log.i(TAG, "CA Certificate Sync Completed"); - resetAlarm("registrationPacketUploadJob"); - result.success(syncResult("CACertificatesSync", 6, masterDataService.onResponseComplete())); - }, isManualSync, jobId); + if (isManualSync && isExcludedJob(jobId)) { + result.success(syncResult("CACertificatesSync", 6, "")); + return; + } + onSyncJobStart(); + try { + masterDataService.syncCACertificates(() -> { + Log.i(TAG, "CA Certificate Sync Completed"); + resetAlarm("registrationPacketUploadJob"); + String errorCode = masterDataService.onResponseComplete(); + boolean success = errorCode == null || errorCode.isEmpty(); + onSyncJobComplete(jobId, success, isManualSync); + result.success(syncResult("CACertificatesSync", 6, errorCode)); + }, isManualSync, jobId); + } catch (Exception e) { + Log.e(TAG, "CA Certificate Sync Failed.", e); + e.printStackTrace(); + onSyncJobComplete(jobId, false, isManualSync); + result.error(e); + } } @Override public void batchJob(@NonNull MasterDataSyncPigeon.Result result) { - batchJob.syncRegistrationPackets(this.context); + batchJob.syncRegistrationPackets(this.context, null); result.success("Registration Packet Sync Completed."); } @@ -286,28 +365,42 @@ public void getReasonList(@NonNull String langCode, @NonNull MasterDataSyncPigeo @Override public void getPreRegIds(@NonNull String jobId, @NonNull MasterDataSyncPigeon.Result result) { + onSyncJobStart(); if (NetworkUtils.isNetworkConnected(this.context)) { try { preRegistrationDataSyncService.fetchPreRegistrationIds(() -> { Log.i(TAG, "Application Id's Sync Completed"); result.success("Application Id's Sync Completed."); + onSyncJobComplete(jobId, true, false); }, jobId); } catch (Exception e) { e.printStackTrace(); + onSyncJobComplete(jobId, false, false); } + } else { + onSyncJobComplete(jobId, false, false); } } @Override public void getKernelCertsSync(@NonNull Boolean isManualSync, @NonNull String jobId, @NonNull MasterDataSyncPigeon.Result result) { + if (isManualSync && isExcludedJob(jobId)) { + result.success(syncResult("KernelCertsSync", 7, "")); + return; + } + onSyncJobStart(); try { masterDataService.syncCertificate(() -> { Log.i(TAG, "Policy Key Sync Completed"); - result.success(syncResult("KernelCertsSync", 7, masterDataService.onResponseComplete())); + String errorCode = masterDataService.onResponseComplete(); + boolean success = errorCode == null || errorCode.isEmpty(); + onSyncJobComplete(jobId, success, isManualSync); + result.success(syncResult("KernelCertsSync", 7, errorCode)); }, KERNEL_APP_ID, "SIGN", "SERVER-RESPONSE", "SIGN-VERIFY", isManualSync, jobId); } catch (Exception e) { e.printStackTrace(); + onSyncJobComplete(jobId, false, isManualSync); } } @@ -360,6 +453,7 @@ void resetAlarm(String api) { @Override public void deleteAuditLogs(@NonNull String jobId, @NonNull MasterDataSyncPigeon.Result result) { try { + onSyncJobStart(); boolean deletedRes = auditManagerService.deleteAuditLogs(); // Also persist timestamps so UI can show Last/Next immediately when triggered manually try { @@ -371,8 +465,10 @@ public void deleteAuditLogs(@NonNull String jobId, @NonNull MasterDataSyncPigeon Log.e(TAG, "Failed to store CA certificates sync last sync time", e); Toast.makeText(context, "Failed to Deleted Audit logs", Toast.LENGTH_LONG).show(); } + onSyncJobComplete(jobId, deletedRes, true); result.success(deletedRes); } catch (Exception e) { + onSyncJobComplete(jobId, false, true); result.error(e); Toast.makeText(context, "Failed to deleted Audit logs", Toast.LENGTH_LONG).show(); } @@ -381,12 +477,15 @@ public void deleteAuditLogs(@NonNull String jobId, @NonNull MasterDataSyncPigeon @Override public void deletePreRegRecords(@NonNull String jobId, @NonNull MasterDataSyncPigeon.Result result) { try { + onSyncJobStart(); // Call fetchAndDeleteRecords from PreRegistrationDataSyncService preRegistrationDataSyncService.fetchAndDeleteRecords(); masterDataService.logLastSyncCompletionDateTime(jobId); Toast.makeText(context, "Deleted Pre-reg records", Toast.LENGTH_LONG).show(); + onSyncJobComplete(jobId, true, true); result.success(true); } catch (Exception e) { + onSyncJobComplete(jobId, false, true); result.error(e); Toast.makeText(context, "Failed to deleted Pre-reg records", Toast.LENGTH_LONG).show(); } @@ -395,11 +494,14 @@ public void deletePreRegRecords(@NonNull String jobId, @NonNull MasterDataSyncPi @Override public void deleteRegistrationPackets(@NonNull String jobId, @NonNull MasterDataSyncPigeon.Result result) { try { + onSyncJobStart(); packetService.deleteRegistrationPackets(); masterDataService.logLastSyncCompletionDateTime(jobId); Toast.makeText(context, "Deleted Registration packets", Toast.LENGTH_LONG).show(); + onSyncJobComplete(jobId, true, true); result.success(true); } catch (Exception e) { + onSyncJobComplete(jobId, false, true); Log.e(TAG, "Failed to delete registration packets", e); result.error(e); Toast.makeText(context, "Failed to delete Registration packets", Toast.LENGTH_LONG).show(); @@ -409,11 +511,14 @@ public void deleteRegistrationPackets(@NonNull String jobId, @NonNull MasterData @Override public void syncPacketStatus(@NonNull String jobId, @NonNull MasterDataSyncPigeon.Result result) { try { + onSyncJobStart(); packetService.syncAllPacketStatus(); masterDataService.logLastSyncCompletionDateTime(jobId); Log.i(TAG, "Packet status sync job completed"); + onSyncJobComplete(jobId, true, true); result.success(true); } catch (Exception e) { + onSyncJobComplete(jobId, false, true); Log.e(TAG, "Failed to sync packet status", e); result.error(e); } @@ -444,6 +549,9 @@ public void getActiveSyncJobs(@NonNull MasterDataSyncPigeon.Result> List value = new ArrayList<>(); try { for (SyncJobDef job : list) { + if (job.getId() == null) { + continue; + } value.add(objectMapper.writeValueAsString(job)); } } catch (Exception e) { @@ -523,78 +631,108 @@ public void executeJobByApiName(String jobApiName, Context context) { // Get job ID from database for tracking last/next sync String jobId = getJobIdByApiName(jobApiName); + onSyncJobStart(); // Execute appropriate sync job switch (jobApiName) { case "registrationPacketUploadJob": - batchJob.syncRegistrationPackets(context); + batchJob.syncRegistrationPackets(context, () -> { + Log.d(getClass().getSimpleName(), "Registration packet upload job completed"); + onSyncJobComplete(jobId, true, false); + }); break; case "packetSyncStatusJob": packetService.syncAllPacketStatus(); + onSyncJobComplete(jobId, true, false); break; case "masterSyncJob": masterDataService.syncMasterData(() -> { Log.d(getClass().getSimpleName(), "Master data sync callback"); - }, 0, true, jobId); + String errorCode = masterDataService.onResponseComplete(); + boolean success = errorCode == null || errorCode.isEmpty(); + onSyncJobComplete(jobId, success, false); + }, 0, false, jobId); break; case "synchConfigDataJob": masterDataService.syncGlobalParamsData(() -> { Log.d(getClass().getSimpleName(), "Config data sync callback"); - }, true, jobId); + String errorCode = masterDataService.onResponseComplete(); + boolean success = errorCode == null || errorCode.isEmpty(); + onSyncJobComplete(jobId, success, false); + }, false, jobId); break; case "userDetailServiceJob": masterDataService.syncUserDetails(() -> { Log.d(getClass().getSimpleName(), "User details sync callback"); - }, true, jobId); + String errorCode = masterDataService.onResponseComplete(); + boolean success = errorCode == null || errorCode.isEmpty(); + onSyncJobComplete(jobId, success, false); + }, false, jobId); break; case "keyPolicySyncJob": CenterMachineDto centerMachineDto = masterDataService.getRegistrationCenterMachineDetails(); if (centerMachineDto != null && centerMachineDto.getMachineRefId() != null) { masterDataService.syncCertificate(() -> { Log.d(getClass().getSimpleName(), "Policy key sync callback"); - }, REG_APP_ID, centerMachineDto.getMachineRefId(), REG_APP_ID, centerMachineDto.getMachineRefId(), true, jobId); + String errorCode = masterDataService.onResponseComplete(); + boolean success = errorCode == null || errorCode.isEmpty(); + onSyncJobComplete(jobId, success, false); + }, REG_APP_ID, centerMachineDto.getMachineRefId(), REG_APP_ID, centerMachineDto.getMachineRefId(), false, jobId); } else { Log.w(getClass().getSimpleName(), "Skipping keyPolicySyncJob - machine details not available"); + onSyncJobComplete(jobId, false, false); } break; case "publicKeySyncJob": // Public key sync for KERNEL app (SIGN certificates) masterDataService.syncCertificate(() -> { Log.d(getClass().getSimpleName(), "Public key sync callback"); - }, KERNEL_APP_ID, "SIGN", "SERVER-RESPONSE", "SIGN-VERIFY", true, jobId); + String errorCode = masterDataService.onResponseComplete(); + boolean success = errorCode == null || errorCode.isEmpty(); + onSyncJobComplete(jobId, success, false); + }, KERNEL_APP_ID, "SIGN", "SERVER-RESPONSE", "SIGN-VERIFY", false, jobId); break; case "syncCertificateJob": // CA certificate sync masterDataService.syncCACertificates(() -> { Log.d(getClass().getSimpleName(), "CA cert sync callback"); - }, true, jobId); + String errorCode = masterDataService.onResponseComplete(); + boolean success = errorCode == null || errorCode.isEmpty(); + onSyncJobComplete(jobId, success, false); + }, false, jobId); break; case "preRegistrationDataSyncJob": preRegistrationDataSyncService.fetchPreRegistrationIds(() -> { Log.i(TAG, "Application Id's Sync Completed"); + onSyncJobComplete(jobId, true, false); }, jobId); break; case "deleteAuditLogsJob": auditManagerService.deleteAuditLogs(); masterDataService.logLastSyncCompletionDateTime(jobId); + onSyncJobComplete(jobId, true, false); break; case "preRegistrationPacketDeletionJob": preRegistrationDataSyncService.fetchAndDeleteRecords(); masterDataService.logLastSyncCompletionDateTime(jobId); + onSyncJobComplete(jobId, true, false); break; case "registrationDeletionJob": packetService.deleteRegistrationPackets(); masterDataService.logLastSyncCompletionDateTime(jobId); Log.i(TAG, "Registration packet deletion job completed"); + onSyncJobComplete(jobId, true, false); break; default: Log.w(getClass().getSimpleName(), "Unknown job: " + jobApiName); + onSyncJobComplete(jobId, false, false); } Log.d(getClass().getSimpleName(), "Completed: " + jobApiName); } catch (Exception e) { + onSyncJobComplete(getJobIdByApiName(jobApiName), false, false); Log.e(getClass().getSimpleName(), "Job failed: " + jobApiName, e); } }).start(); @@ -611,4 +749,121 @@ private String getJobIdByApiName(String apiName) { } return ""; // Return empty string if not found } + + private Set getExcludedJobIds() { + Set excluded = new HashSet<>(); + addJobIdsFromString(excluded, globalParamRepository.getCachedStringJobsOffline()); + addJobIdsFromString(excluded, globalParamRepository.getCachedStringJobsUntagged()); + return excluded; + } + + private void addJobIdsFromString(Set target, String value) { + if (value == null || value.trim().isEmpty()) { + return; + } + for (String jobId : value.split(RegistrationConstants.COMMA)) { + String trimmed = jobId.trim(); + if (!trimmed.isEmpty()) { + target.add(trimmed); + } + } + } + + /** True if job is in offline or untagged list (excluded from auto sync and manual sync execution). */ + private boolean isExcludedJob(String jobId) { + return jobId != null && !jobId.trim().isEmpty() && getExcludedJobIds().contains(jobId.trim()); + } + + private void onSyncJobStart() { + runningSyncJobs.incrementAndGet(); + cancelPendingRestartPrompt(); + } + + private void onSyncJobComplete(String jobId, boolean success, boolean isManualSync) { + boolean shouldPrompt = false; + synchronized (restartLock) { + if (runningSyncJobs.get() > 0) { + runningSyncJobs.decrementAndGet(); + } + // Only request restart when a restartable job completed successfully during manual sync + if (success && isRestartableJob(jobId) && isManualSync) { + restartRequested.set(true); + } + if (runningSyncJobs.get() == 0 && restartRequested.get()) { + shouldPrompt = true; + } + } + if (shouldPrompt) { + scheduleRestartPrompt(); + } + } + + private boolean isRestartableJob(String jobId) { + if (jobId == null || jobId.trim().isEmpty()) { + return false; + } + String value = globalParamRepository.getCachedStringJobsRestart(); + if (value == null || value.trim().isEmpty()) { + return false; + } + String target = jobId.trim(); + for (String id : value.split(RegistrationConstants.COMMA)) { + if (target.equals(id.trim())) { + return true; + } + } + return false; + } + + private void scheduleRestartPrompt() { + synchronized (restartLock) { + // Ensure any previously scheduled prompt is cancelled before scheduling a new one + cancelPendingRestartPromptLocked(); + pendingRestartPrompt = () -> { + boolean showPrompt = false; + synchronized (restartLock) { + if (runningSyncJobs.get() == 0 && restartRequested.get()) { + restartRequested.set(false); + showPrompt = true; + } + } + if (showPrompt) { + showRestartDialog(); + } + }; + // Delay to allow any queued syncs to start + restartHandler.postDelayed(pendingRestartPrompt, 2000); + } + } + + private void cancelPendingRestartPrompt() { + synchronized (restartLock) { + cancelPendingRestartPromptLocked(); + } + } + + /** + * Internal helper that assumes the caller already holds restartLock. + */ + private void cancelPendingRestartPromptLocked() { + if (pendingRestartPrompt != null) { + restartHandler.removeCallbacks(pendingRestartPrompt); + pendingRestartPrompt = null; + } + } + + private static final String SYNC_RESTART_CHANNEL = "io.mosip.registration_client/sync_restart"; + + private void showRestartDialog() { + if (flutterBinaryMessenger == null) { + Log.w(TAG, "Restart prompt skipped: Flutter binary messenger not set"); + return; + } + try { + new MethodChannel(flutterBinaryMessenger, SYNC_RESTART_CHANNEL) + .invokeMethod("showRestartDialog", null); + } catch (Exception e) { + Log.e(TAG, "Failed to request Flutter restart dialog", e); + } + } } diff --git a/android/app/src/main/java/io/mosip/registration_client/utils/BatchJob.java b/android/app/src/main/java/io/mosip/registration_client/utils/BatchJob.java index dfc74924a..d2e4eec08 100644 --- a/android/app/src/main/java/io/mosip/registration_client/utils/BatchJob.java +++ b/android/app/src/main/java/io/mosip/registration_client/utils/BatchJob.java @@ -71,7 +71,7 @@ private List getRegistrationList(List statusList) { return registrationList; } - public void syncRegistrationPackets(Context context) { + public void syncRegistrationPackets(Context context, Runnable onComplete) { Log.d(getClass().getSimpleName(), "Sync Packets in Batch Job"); List registrationList = getRegistrationList(Arrays.asList(PacketClientStatus.APPROVED.name(), PacketClientStatus.REJECTED.name())); final Integer[] remainingPack = {registrationList.size(), 0}; @@ -80,7 +80,7 @@ public void syncRegistrationPackets(Context context) { CustomToast newToast = new CustomToast(activity); if (registrationList.isEmpty()) { - uploadRegistrationPackets(context); + uploadRegistrationPackets(context, onComplete); return; } for (Registration value : registrationList) { @@ -126,18 +126,29 @@ public void onComplete(String RID, PacketTaskStatus status) { newToast.showToast(); Log.d(getClass().getSimpleName(), "Last Packet" + RID); - uploadRegistrationPackets(context); + uploadRegistrationPackets(context, onComplete); } } }); } catch (Exception e) { - syncAndUploadInProgressStatus = false; Log.e(getClass().getSimpleName(), e.getMessage()); + // If exception occurs, decrement counter and check if all packets are done + remainingPack[0] -= 1; + if (remainingPack[0] == 0) { + // All packets processed (either completed or failed) + syncAndUploadInProgressStatus = false; + Log.d(getClass().getSimpleName(), "Last Packet (exception)"); + if (onComplete != null) { + uploadRegistrationPackets(context, onComplete); + } else { + uploadRegistrationPackets(context, null); + } + } } } } - public void uploadRegistrationPackets(Context context) { + public void uploadRegistrationPackets(Context context, Runnable onComplete) { Log.d(getClass().getSimpleName(), "Upload Packets in Batch Job"); List registrationList = getRegistrationList(Arrays.asList(PacketClientStatus.SYNCED.name(), PacketClientStatus.EXPORTED.name())); @@ -145,6 +156,14 @@ public void uploadRegistrationPackets(Context context) { final Integer[] remainingPack = {packetSize, 0}; CustomToast newToast = new CustomToast(activity); + if (registrationList.isEmpty()) { + // If no packets to upload, call completion callback if provided + if (onComplete != null) { + onComplete.run(); + } + return; + } + for (Registration value : registrationList) { try { syncAndUploadInProgressStatus = true; @@ -186,6 +205,11 @@ public void onComplete(String RID, PacketTaskStatus status) { } newToast.setText(message); newToast.showToast(); + + // Call completion callback when all uploads finish + if (onComplete != null) { + onComplete.run(); + } } } }); @@ -193,6 +217,28 @@ public void onComplete(String RID, PacketTaskStatus status) { syncAndUploadInProgressStatus = false; Log.e(getClass().getSimpleName(), e.getMessage()); auditManagerService.audit(AuditEvent.PACKET_INTERNAL_ERROR, Components.REG_PACKET_LIST, e.getMessage()); + // If exception occurs, decrement counter and check if all packets are done + remainingPack[0] -= 1; + if (remainingPack[0] == 0) { + // All packets processed (either completed or failed) + syncAndUploadInProgressStatus = false; + Integer failed = packetSize - remainingPack[1]; + newToast.setIcon(R.drawable.done); + String message = "Upload Packet Status :"; + if (remainingPack[1] != 0) { + message = message + String.format(" %s/%s Success", remainingPack[1], packetSize); + } + if (failed != 0) { + message = message + String.format(" %s/%s Failed", failed, packetSize); + } + newToast.setText(message); + newToast.showToast(); + + // Call completion callback when all uploads finish + if (onComplete != null) { + onComplete.run(); + } + } } } } diff --git a/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/constant/RegistrationConstants.java b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/constant/RegistrationConstants.java index 966fd27d9..7f4ea26ba 100644 --- a/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/constant/RegistrationConstants.java +++ b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/constant/RegistrationConstants.java @@ -153,6 +153,10 @@ public class RegistrationConstants { public static final String REG_PAK_MAX_CNT_APPRV_LIMIT = "mosip.registration.reg_pak_max_cnt_apprv_limit"; public static final String PACKET_STORE_LOCATION = "mosip.registration.registration_packet_store_location"; + public static final String JOBS_OFFLINE = "mosip.registration.jobs.offline"; + public static final String JOBS_UNTAGGED = "mosip.registration.jobs.unTagged"; + public static final String JOBS_RESTART = "mosip.registration.jobs.restart"; + // Sync status validation constants public static final String MOSIP_REGISTRATION = "mosip.registration."; public static final String DOT = "."; diff --git a/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/repository/GlobalParamRepository.java b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/repository/GlobalParamRepository.java index 01470f3c6..008097c11 100644 --- a/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/repository/GlobalParamRepository.java +++ b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/repository/GlobalParamRepository.java @@ -254,10 +254,23 @@ public String getCachedStringFieldsToRetainOnPridFetch(){ public int getCachedIntRegMaxCountApproveLimit(){ return getCachedIntegerGlobalParam(RegistrationConstants.REG_PAK_MAX_CNT_APPRV_LIMIT); } + public String getCachedStringPacketStoreLocation() { return globalParamMap.get(RegistrationConstants.PACKET_STORE_LOCATION); } + public String getCachedStringJobsOffline() { + return globalParamMap.get(RegistrationConstants.JOBS_OFFLINE); + } + + public String getCachedStringJobsUntagged() { + return globalParamMap.get(RegistrationConstants.JOBS_UNTAGGED); + } + + public String getCachedStringJobsRestart() { + return globalParamMap.get(RegistrationConstants.JOBS_RESTART); + } + /** * Refresh configuration cache by merging global params with local preferences */ diff --git a/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/service/RegistrationServiceImpl.java b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/service/RegistrationServiceImpl.java index 4d93f3867..ee64fee04 100644 --- a/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/service/RegistrationServiceImpl.java +++ b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/service/RegistrationServiceImpl.java @@ -579,7 +579,7 @@ public List> getAudits() { private void doPreChecksBeforeRegistration(CenterMachineDto centerMachineDto) throws Exception { //free space validation - if (validatingDiskSpace()) { + if (isDiskSpaceAvailable()) { throw new ClientCheckedException("PAK_DISK_SPACE_LOW"); } @@ -611,7 +611,7 @@ private void doPreChecksBeforeRegistration(CenterMachineDto centerMachineDto) th } } - private boolean validatingDiskSpace() { + private boolean isDiskSpaceAvailable() { int minSpaceRequiredMB = globalParamRepository.getCachedIntegerDiskSpaceSize(); if (minSpaceRequiredMB <= 0) { minSpaceRequiredMB = DEFAULT_MIN_SPACE_REQUIRED_MB; diff --git a/android/packetmanager/src/main/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImpl.java b/android/packetmanager/src/main/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImpl.java index 4fcafc2ba..26963464e 100644 --- a/android/packetmanager/src/main/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImpl.java +++ b/android/packetmanager/src/main/java/io/mosip/registration/packetmanager/service/PosixAdapterServiceImpl.java @@ -75,9 +75,6 @@ private void initPosixAdapterService(Context context) { File baseDir = StorageUtils.getPacketStorageDir(context); if (baseDir.exists() || baseDir.mkdirs()) { BASE_LOCATION = baseDir.getAbsolutePath(); - } else { - Log.e(TAG, "Failed to initialize packet storage directory: " + baseDir.getAbsolutePath()); - BASE_LOCATION = null; } } diff --git a/assets/l10n/app_ar.arb b/assets/l10n/app_ar.arb index 5c47f07f0..8d6ef617f 100644 --- a/assets/l10n/app_ar.arb +++ b/assets/l10n/app_ar.arb @@ -360,6 +360,9 @@ "local_preferences_saved_msg": "تم حفظ التفضيلات المحلية بنجاح. يلزم إعادة تشغيل التطبيق لرؤية التغييرات. هل ترغب في الإنهاء الآن؟", "search_for_key": "ابحث عن المفتاح", "no_devices_found": "لم يتم العثور على أجهزة", - "connect_devices_and_scan": "يرجى توصيل أجهزتك والضغط على 'مسح' لاكتشافها" + "connect_devices_and_scan": "يرجى توصيل أجهزتك والضغط على 'مسح' لاكتشافها", + "search_for_key": "ابحث عن المفتاح", + "sync_restart_dialog_message": "سيتم إعادة تشغيل التطبيق بمجرد النقر على إعادة التشغيل، وسيتم توجيهك إلى صفحة تسجيل الدخول.", + "sync_restart_button": "إعادة التشغيل" } diff --git a/assets/l10n/app_en.arb b/assets/l10n/app_en.arb index 8892ef679..72b55b737 100644 --- a/assets/l10n/app_en.arb +++ b/assets/l10n/app_en.arb @@ -360,5 +360,8 @@ "local_preferences_saved_msg": "Local Preferences have been saved successfully. Application restart is needed to see the changes. Do you want to quit now?", "search_for_key": "Search for Key", "no_devices_found": "No devices found", - "connect_devices_and_scan": "Please connect your devices and tap 'Scan' to detect them" + "connect_devices_and_scan": "Please connect your devices and tap 'Scan' to detect them", + "search_for_key": "Search for Key", + "sync_restart_dialog_message": "The app will restart once you click Restart, and you will be redirected to the login page.", + "sync_restart_button": "Restart" } diff --git a/assets/l10n/app_fr.arb b/assets/l10n/app_fr.arb index 899920892..ccff36ba3 100644 --- a/assets/l10n/app_fr.arb +++ b/assets/l10n/app_fr.arb @@ -360,6 +360,9 @@ "local_preferences_saved_msg": "Les préférences locales ont été enregistrées avec succès. Le redémarrage de l'application est nécessaire pour voir les changements. Voulez-vous quitter maintenant ?", "search_for_key": "Rechercher une clé", "no_devices_found": "Aucun appareil trouvé", - "connect_devices_and_scan": "Veuillez connecter vos appareils et appuyer sur 'ANALYSE' pour les détecter" + "connect_devices_and_scan": "Veuillez connecter vos appareils et appuyer sur 'ANALYSE' pour les détecter", + "search_for_key": "Rechercher une clé", + "sync_restart_dialog_message": "L'application redémarrera une fois que vous aurez cliqué sur Redémarrer, et vous serez redirigé vers la page de connexion.", + "sync_restart_button": "Redémarrer" } diff --git a/assets/l10n/app_hi.arb b/assets/l10n/app_hi.arb index 54e16ebbb..e72569388 100644 --- a/assets/l10n/app_hi.arb +++ b/assets/l10n/app_hi.arb @@ -360,5 +360,8 @@ "local_preferences_saved_msg": "स्थानीय प्राथमिकताएँ सफलतापूर्वक सहेज ली गई हैं। बदलाव देखने के लिए एप्लिकेशन को पुनः शुरू करना आवश्यक है। क्या आप अभी बाहर निकलना चाहते हैं?", "search_for_key": "कुंजी खोजें", "no_devices_found": "कोई डिवाइस नहीं मिला", - "connect_devices_and_scan": "कृपया अपने डिवाइस कनेक्ट करें और उन्हें खोजने के लिए 'स्कैन' पर टैप करें" + "connect_devices_and_scan": "कृपया अपने डिवाइस कनेक्ट करें और उन्हें खोजने के लिए 'स्कैन' पर टैप करें", + "search_for_key": "कुंजी खोजें", + "sync_restart_dialog_message": "जैसे ही आप पुनः आरंभ करें पर क्लिक करेंगे ऐप पुनः आरंभ हो जाएगा, और आपको लॉगिन पृष्ठ पर पुनः निर्देशित किया जाएगा।", + "sync_restart_button": "पुनः आरंभ करें" } diff --git a/assets/l10n/app_kn.arb b/assets/l10n/app_kn.arb index 9f228a3f6..a5ebe4b08 100644 --- a/assets/l10n/app_kn.arb +++ b/assets/l10n/app_kn.arb @@ -360,5 +360,8 @@ "local_preferences_saved_msg": "ಸ್ಥಳೀಯ ಆದ್ಯತೆಗಳನ್ನು ಯಶಸ್ವಿಯಾಗಿ ಸಂಗ್ರಹಿಸಲಾಗಿದೆ. ಬದಲಾವಣೆಗಳನ್ನು ನೋಡಲು ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಬೇಕು. ನೀವು ಈಗ ನಿರ್ಗಮಿಸಲು ಬಯಸುವಿರಾ?", "search_for_key": "ಕೀಗಾಗಿ ಹುಡುಕಿ", "no_devices_found": "ಯಾವುದೇ ಸಾಧನಗಳು ಕಂಡುಬಂದಿಲ್ಲ", - "connect_devices_and_scan": "ದಯವಿಟ್ಟು ನಿಮ್ಮ ಸಾಧನಗಳನ್ನು ಸಂಪರ್ಕಿಸಿ ಮತ್ತು ಅವುಗಳನ್ನು ಪತ್ತೆಹಚ್ಚಲು 'ಸ್ಕ್ಯಾನ್' ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ" + "connect_devices_and_scan": "ದಯವಿಟ್ಟು ನಿಮ್ಮ ಸಾಧನಗಳನ್ನು ಸಂಪರ್ಕಿಸಿ ಮತ್ತು ಅವುಗಳನ್ನು ಪತ್ತೆಹಚ್ಚಲು 'ಸ್ಕ್ಯಾನ್' ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ", + "search_for_key": "ಕೀಗಾಗಿ ಹುಡುಕಿ", + "sync_restart_dialog_message": "ನೀವು ಮರುಪ್ರಾರಂಭ ಕ್ಲಿಕ್ ಮಾಡಿದ ನಂತರ ಅಪ್ಲಿಕೇಶನ್ ಮರುಪ್ರಾರಂಭವಾಗುತ್ತದೆ ಮತ್ತು ನಿಮ್ಮನ್ನು ಲಾಗಿನ್ ಪುಟಕ್ಕೆ ಮರುನಿರ್ದೇಶಿಸಲಾಗುತ್ತದೆ.", + "sync_restart_button": "ಮರುಪ್ರಾರಂಭ" } diff --git a/assets/l10n/app_ta.arb b/assets/l10n/app_ta.arb index 922e60dc8..befaa0eb9 100644 --- a/assets/l10n/app_ta.arb +++ b/assets/l10n/app_ta.arb @@ -369,5 +369,8 @@ "local_preferences_saved_msg": "உள்நாட்டு விருப்பங்கள் வெற்றிகரமாக சேமிக்கப்பட்டுள்ளன. மாற்றங்களைப் பார்க்க பயன்பாட்டை மறுதொடக்கம் செய்ய வேண்டும். நீங்கள் இப்போது வெளியேற விரும்புகிறீர்களா?", "search_for_key": "விசையைத் தேடவும்", "no_devices_found": "சாதனங்கள் எதுவும் கண்டுபிடிக்கப்படவில்லை", - "connect_devices_and_scan": "தயவுசெய்து உங்கள் சாதனங்களை இணைத்து, அவற்றைக் கண்டறிய 'ஊடுகதிர்' என்பதைத் தட்டவும்" + "connect_devices_and_scan": "தயவுசெய்து உங்கள் சாதனங்களை இணைத்து, அவற்றைக் கண்டறிய 'ஊடுகதிர்' என்பதைத் தட்டவும்", + "search_for_key": "விசையைத் தேடவும்", + "sync_restart_dialog_message": "மறுதொடக்கம் என்பதைக் கிளிக் செய்தவுடன் பயன்பாடு மறுதொடங்கும், மற்றும் நீங்கள் உள்நுழைவு பக்கத்திற்கு திருப்பிவிடப்படுவீர்கள்.", + "sync_restart_button": "மறுதொடக்கம்" } diff --git a/lib/main.dart b/lib/main.dart index db4d4d40a..70ce3b9aa 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -20,15 +20,21 @@ import 'package:registration_client/provider/sync_provider.dart'; import 'package:registration_client/ui/login_page.dart'; import 'package:registration_client/utils/app_config.dart'; import 'package:flutter_driver/driver_extension.dart'; +import 'package:flutter/services.dart'; import 'package:registration_client/utils/inactivity_tracker.dart'; +import 'package:restart_app/restart_app.dart'; final GlobalKey rootNavigatorKey = GlobalKey(); final GlobalKey rootScaffoldMessengerKey = GlobalKey(); +/// MethodChannel name used by Android to request showing the sync-complete restart dialog. +const String _syncRestartChannel = 'io.mosip.registration_client/sync_restart'; + void main() async { enableFlutterDriverExtension(enableTextEntryEmulation: false); WidgetsFlutterBinding.ensureInitialized(); + _setupSyncRestartChannel(); final GlobalProvider appLanguage = GlobalProvider(); await FlutterConfig.loadEnvVariables(); await appLanguage.fetchLocale(); @@ -37,6 +43,83 @@ void main() async { ); } +/// Max retries when showing the sync-restart dialog if context/localizations +/// are not ready yet (e.g. native call before widget tree is mounted). +const int _syncRestartDialogMaxRetries = 10; + +void _setupSyncRestartChannel() { + const MethodChannel(_syncRestartChannel).setMethodCallHandler((MethodCall call) async { + if (call.method == 'showRestartDialog') { + int attempt = 0; + + void tryShowRestartDialog() { + attempt++; + final context = rootNavigatorKey.currentContext; + if (context == null) { + if (attempt <= _syncRestartDialogMaxRetries) { + debugPrint( + 'SyncRestart: context not ready (attempt $attempt/$_syncRestartDialogMaxRetries), ' + 'scheduling retry on next frame.', + ); + WidgetsBinding.instance.addPostFrameCallback((_) => tryShowRestartDialog()); + } else { + debugPrint( + 'SyncRestart: WARNING — Restart prompt was not shown: navigator context was null ' + 'after $_syncRestartDialogMaxRetries attempts. User may need to restart the app manually.', + ); + } + return; + } + final loc = AppLocalizations.of(context); + if (loc == null) { + if (attempt <= _syncRestartDialogMaxRetries) { + debugPrint( + 'SyncRestart: localizations not ready (attempt $attempt/$_syncRestartDialogMaxRetries), ' + 'scheduling retry on next frame.', + ); + WidgetsBinding.instance.addPostFrameCallback((_) => tryShowRestartDialog()); + } else { + debugPrint( + 'SyncRestart: WARNING — Restart prompt was not shown: AppLocalizations was null ' + 'after $_syncRestartDialogMaxRetries attempts. User may need to restart the app manually.', + ); + } + return; + } + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext dialogContext) => AlertDialog( + title: Text(loc.sync_completed_succesfully), + content: Text(loc.sync_restart_dialog_message), + actions: [ + FilledButton( + onPressed: () { + Navigator.of(dialogContext).pop(); + Restart.restartApp(); + }, + child: Text(loc.sync_restart_button), + ), + ], + ), + ); + } + + final context = rootNavigatorKey.currentContext; + if (context != null) { + tryShowRestartDialog(); + } else { + debugPrint( + 'SyncRestart: native call arrived before widget tree ready, ' + 'scheduling restart dialog on next frame.', + ); + WidgetsBinding.instance.addPostFrameCallback((_) => tryShowRestartDialog()); + } + } + return null; + }); +} + Future _handleAutoLogout() async { final ctx = rootNavigatorKey.currentContext; if (ctx == null) return; // Safety guard diff --git a/lib/platform_android/sync_response_service_impl.dart b/lib/platform_android/sync_response_service_impl.dart index d33ab8227..0a58f4198 100644 --- a/lib/platform_android/sync_response_service_impl.dart +++ b/lib/platform_android/sync_response_service_impl.dart @@ -52,10 +52,10 @@ class SyncResponseServiceImpl implements SyncResponseService { } @override - Future getIDSchemaSync(bool isManualSync) async { + Future getIDSchemaSync(bool isManualSync, String jobId) async { late Sync syncResponse; try { - syncResponse = await SyncApi().getIDSchemaSync(isManualSync); + syncResponse = await SyncApi().getIDSchemaSync(isManualSync, jobId); } on PlatformException { debugPrint('IDSchemaSync Api call failed, PlatformException'); } catch (e) { diff --git a/lib/platform_spi/sync_response_service.dart b/lib/platform_spi/sync_response_service.dart index 872cab2f6..0d5bbf8d7 100644 --- a/lib/platform_spi/sync_response_service.dart +++ b/lib/platform_spi/sync_response_service.dart @@ -13,7 +13,7 @@ abstract class SyncResponseService { Future getPolicyKeySync(bool isManualSync, String jobId); Future getGlobalParamsSync(bool isManualSync, String jobId); Future getUserDetailsSync(bool isManualSync, String jobId); - Future getIDSchemaSync(bool isManualSync); + Future getIDSchemaSync(bool isManualSync, String jobId); Future getMasterDataSync(bool isManualSync, String jobId); Future getCaCertsSync(bool isManualSync, String jobId); Future batchJob(); diff --git a/lib/provider/sync_provider.dart b/lib/provider/sync_provider.dart index f7b14ea80..65ba4390e 100644 --- a/lib/provider/sync_provider.dart +++ b/lib/provider/sync_provider.dart @@ -163,7 +163,7 @@ class SyncProvider with ChangeNotifier { }); await syncResponseService - .getIDSchemaSync(false) + .getIDSchemaSync(false, findJobIdByApiName("latestIdSchemaSyncJob")) .then((Sync getAutoSync) async { setCurrentProgressType(getAutoSync.syncType!); if (getAutoSync.errorCode == "") { @@ -237,7 +237,7 @@ class SyncProvider with ChangeNotifier { Sync syncResult = await syncResponseService.getMasterDataSync(true, findJobIdByApiName("masterSyncJob")); if (syncResult.errorCode != null && syncResult.errorCode!.isEmpty) { - syncResult = await syncResponseService.getIDSchemaSync(true); + syncResult = await syncResponseService.getIDSchemaSync(true, findJobIdByApiName("latestIdSchemaSyncJob")); if (syncResult.errorCode != null && syncResult.errorCode!.isEmpty) { syncResult = await syncResponseService.getUserDetailsSync(true, findJobIdByApiName("userDetailServiceJob")); if (syncResult.errorCode != null && syncResult.errorCode!.isEmpty) { diff --git a/pigeon/master_data_sync.dart b/pigeon/master_data_sync.dart index 315e1c47c..563ab2252 100644 --- a/pigeon/master_data_sync.dart +++ b/pigeon/master_data_sync.dart @@ -29,7 +29,7 @@ abstract class SyncApi { Sync getUserDetailsSync(bool isManualSync, String jobId); @async - Sync getIDSchemaSync(bool isManualSync); + Sync getIDSchemaSync(bool isManualSync, String jobId); @async Sync getMasterDataSync(bool isManualSync, String jobId);