dhis2_android_setup_sync
Configure and manage offline-first data synchronization for the DHIS2 Android app using flexible strategies, conflict resolution, and network conditions tailored to your needs.
Instructions
Configure offline-first data synchronization patterns for DHIS2 Android app
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| conflictResolution | No | Strategy for resolving sync conflicts | |
| networkConditions | No | ||
| progressTracking | No | Include sync progress tracking UI | |
| syncScope | No | ||
| syncStrategy | Yes | Data synchronization strategy |
Implementation Reference
- src/index.ts:1262-1271 (handler)Handler function that processes the tool call by invoking generateSyncConfiguration with input arguments and returning the generated sync configuration as markdown content.const syncArgs = args as any; const syncConfig = generateSyncConfiguration(syncArgs); return { content: [ { type: 'text', text: syncConfig, }, ], };
- src/android-generators.ts:553-784 (helper)Main helper function that generates comprehensive Kotlin code for DHIS2 Android sync setup, including SyncManager class, background workers, network monitoring, conflict resolution, progress tracking, and usage examples.export function generateSyncConfiguration(args: any): string { const { syncStrategy, syncScope, conflictResolution, networkConditions, progressTracking } = args; return `# DHIS2 Android Sync Configuration ## Overview This configuration sets up ${syncStrategy} synchronization with ${conflictResolution} conflict resolution. ## Sync Manager Setup \`\`\`kotlin class SyncManager @Inject constructor( private val d2: D2, private val networkManager: NetworkManager, private val syncPreferences: SyncPreferences ) { suspend fun performSync(syncType: SyncType = SyncType.FULL): SyncResult { return when (syncStrategy) { SyncStrategy.MANUAL -> performManualSync(syncType) SyncStrategy.AUTOMATIC -> performAutomaticSync() SyncStrategy.SCHEDULED -> scheduleSync() SyncStrategy.SMART -> performSmartSync() } } private suspend fun performManualSync(syncType: SyncType): SyncResult { if (!canSync()) return SyncResult.Failed("Network conditions not met") return try { ${syncScope.metadata ? 'syncMetadata()' : ''} ${syncScope.dataValues ? 'syncDataValues()' : ''} ${syncScope.events ? 'syncEvents()' : ''} ${syncScope.enrollments ? 'syncEnrollments()' : ''} SyncResult.Success } catch (e: Exception) { handleSyncError(e) } } private suspend fun syncMetadata() { ${progressTracking ? 'updateProgress("Syncing metadata...", 10)' : ''} d2.metadataModule().download().blockingDownload() } private suspend fun syncDataValues() { ${progressTracking ? 'updateProgress("Syncing data values...", 40)' : ''} d2.dataValueModule().dataValueUploader().blockingUpload() } private suspend fun syncEvents() { ${progressTracking ? 'updateProgress("Syncing events...", 70)' : ''} d2.trackerModule().trackedEntityInstances().blockingUpload() d2.eventModule().events().blockingUpload() } private suspend fun syncEnrollments() { ${progressTracking ? 'updateProgress("Syncing enrollments...", 90)' : ''} d2.enrollmentModule().enrollments().blockingUpload() } private fun canSync(): Boolean { ${networkConditions.wifiOnly ? 'if (!networkManager.isWiFiConnected()) return false' : ''} if (!networkManager.isConnected()) return false return true } private fun handleConflict(conflict: ImportConflict): ConflictResolution { return when (conflictResolution) { ConflictResolution.SERVER_WINS -> ConflictResolution.SERVER_WINS ConflictResolution.CLIENT_WINS -> ConflictResolution.CLIENT_WINS ConflictResolution.MERGE -> mergeConflict(conflict) ConflictResolution.USER_PROMPT -> promptUserForResolution(conflict) } } } sealed class SyncResult { object Success : SyncResult() data class Failed(val error: String) : SyncResult() data class PartialSuccess(val details: String) : SyncResult() } enum class SyncStrategy { MANUAL, AUTOMATIC, SCHEDULED, SMART } \`\`\` ## Background Sync Service \`\`\`kotlin @HiltWorker class SyncWorker @AssistedInject constructor( @Assisted context: Context, @Assisted workerParams: WorkerParameters, private val syncManager: SyncManager ) : CoroutineWorker(context, workerParams) { override suspend fun doWork(): Result { return try { val result = syncManager.performSync() when (result) { is SyncResult.Success -> Result.success() is SyncResult.Failed -> Result.retry() is SyncResult.PartialSuccess -> Result.success() } } catch (e: Exception) { Result.failure() } } @AssistedFactory interface Factory { fun create(context: Context, params: WorkerParameters): SyncWorker } } // Schedule periodic sync class SyncScheduler @Inject constructor( private val workManager: WorkManager ) { fun schedulePeriodicSync() { val constraints = Constraints.Builder() ${networkConditions.wifiOnly ? '.setRequiredNetworkType(NetworkType.UNMETERED)' : '.setRequiredNetworkType(NetworkType.CONNECTED)'} ${networkConditions.backgroundSync ? '' : '.setRequiresBatteryNotLow(true)'} .build() val syncRequest = PeriodicWorkRequestBuilder<SyncWorker>( repeatInterval = 15, // minutes repeatIntervalTimeUnit = TimeUnit.MINUTES ).setConstraints(constraints) .build() workManager.enqueueUniquePeriodicWork( "sync_work", ExistingPeriodicWorkPolicy.KEEP, syncRequest ) } } \`\`\` ## Network Monitoring \`\`\`kotlin @Singleton class NetworkManager @Inject constructor( @ApplicationContext private val context: Context ) { private val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager fun isConnected(): Boolean { val network = connectivityManager.activeNetwork ?: return false val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) } fun isWiFiConnected(): Boolean { val network = connectivityManager.activeNetwork ?: return false val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) } fun getNetworkType(): NetworkType { val network = connectivityManager.activeNetwork ?: return NetworkType.NONE val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return NetworkType.NONE return when { capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> NetworkType.WIFI capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> NetworkType.CELLULAR else -> NetworkType.OTHER } } } enum class NetworkType { NONE, WIFI, CELLULAR, OTHER } \`\`\` ${progressTracking ? generateProgressTracking() : ''} ## Usage Example \`\`\`kotlin class MainActivity : AppCompatActivity() { @Inject lateinit var syncManager: SyncManager @Inject lateinit var syncScheduler: SyncScheduler override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Schedule background sync syncScheduler.schedulePeriodicSync() // Manual sync button binding.syncButton.setOnClickListener { lifecycleScope.launch { val result = syncManager.performSync() handleSyncResult(result) } } } private fun handleSyncResult(result: SyncResult) { when (result) { is SyncResult.Success -> { Toast.makeText(this, "Sync completed successfully", Toast.LENGTH_SHORT).show() } is SyncResult.Failed -> { Toast.makeText(this, "Sync failed: \${result.error}", Toast.LENGTH_LONG).show() } is SyncResult.PartialSuccess -> { Toast.makeText(this, "Partial sync: \${result.details}", Toast.LENGTH_SHORT).show() } } } } \`\`\` ## Configuration Summary - **Strategy**: ${syncStrategy} - **Scope**: ${Object.entries(syncScope).filter(([_, enabled]) => enabled).map(([key]) => key).join(', ')} - **Conflict Resolution**: ${conflictResolution} - **Network**: ${networkConditions.wifiOnly ? 'WiFi only' : 'Any connection'}${networkConditions.backgroundSync ? ', Background sync enabled' : ''} - **Progress Tracking**: ${progressTracking ? 'Enabled' : 'Disabled'} ${networkConditions.chunkSize ? `- **Chunk Size**: ${networkConditions.chunkSize}KB` : ''} `; }
- src/permission-system.ts:157-157 (registration)Tool permission registration in TOOL_PERMISSIONS map, requiring 'canConfigureMobile' permission for access.['dhis2_android_setup_sync', 'canConfigureMobile'],