Skip to main content
Glama

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
NameRequiredDescriptionDefault
conflictResolutionNoStrategy for resolving sync conflicts
networkConditionsNo
progressTrackingNoInclude sync progress tracking UI
syncScopeNo
syncStrategyYesData synchronization strategy

Implementation Reference

  • 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, }, ], };
  • 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` : ''} `; }
  • Tool permission registration in TOOL_PERMISSIONS map, requiring 'canConfigureMobile' permission for access.
    ['dhis2_android_setup_sync', 'canConfigureMobile'],

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Dradebo/dhis2-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server