guide dhis 2 du développeur d’android sdk2 compatibility: sdk / core / android 3 aperçu 3.1...

43
Guide DHIS 2 du développeur d’Android SDK Applicable to version 1.3.1 DHIS 2 janvier 2021

Upload: others

Post on 05-Oct-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

Guide DHIS 2 du développeur

d’Android SDK

Applicable to version 1.3.1

DHIS 2

janvier 2021

Page 2: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

Copyright © 2006-2021 DHIS 2

janvier 2021

Historique des révisions

master@

Garantie: CE DOCUMENT EST FOURNI PAR LES AUTEURS ’’ EN L’ETAT ’’ ET TOUTE GARANTIEEXPRESSE OU IMPLICITE, Y COMPRIS, MAIS SANS S’Y LIMITER, LES GARANTIES IMPLICITES DEQUALITÉ MARCHANDE ET D’ADÉQUATION À UN USAGE PARTICULIER SONT DÉCLINEES. ENAUCUN CAS, LES AUTEURS OU CONTRIBUTEURS NE PEUVENT ÊTRE TENUS RESPONSABLES DESDOMMAGES DIRECTS, INDIRECTS, ACCESSOIRES, SPÉCIAUX, EXEMPLAIRES OU ACCESSOIRES (YCOMPRIS, MAIS SANS S’Y LIMITER, L’ACHAT DE MARCHANDISES OU DE SERVICES SUBSTITUÉS;PERTE D’UTILISATION, DE DONNÉES OU DE PROFITS; INTERRUPTION COMMERCIALE) TOUTEFOISCAUSÉE ET SUR TOUTE THÉORIE DE LA RESPONSABILITÉ, QU’IL SOIT DU CONTRAT, UNERESPONSABILITÉ STRICTE OU UN LAC (Y COMPRIS LA NÉGLIGENCE OU AUTREMENT) DÉCOULANTDE TOUTE MANIÈRE DE L’UTILISATION DE CE MANUEL ET DES PRODUITS MENTIONNÉS DANS CEDOCUMENT, MÊME SI MIS À JOUR, TELS DOMMAGES.

Licence: L’autorisation est donnée de copier, distribuer ou modifier ce document selon lestermes de la licence GNU de documentation libre, dans sa version 1.3 ou dans toute versionultérieure publiée par la Free Software Foundation ; sans Section Invariante, sans Texte DePremière De Couverture, et sans Texte De Quatrième De Couverture. Une copie de cette licenceest incluse dans la section intitulée “Licence GNU de documentation libre”: https://www.april.org/files/gfdl.1.3-js.fr.html

Guide DHIS 2 du développeur d’Android SDK Applicable to version 1.3.1

2

Page 3: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

Table des matières

1 À propos de ce guide2 Compatibility: SDK / core / Android3 Aperçu

3.1 Technology overview4 Mise en route

4.1 Installation4.2 D2 initialization

5 Modules and repositories5.1 Dealing with return types: RxJava5.2 Query building

5.2.1 Filters5.2.2 Order by5.2.3 Include nested fields

5.3 Helpers5.4 Module list

6 Base de données6.1 Database scope6.2 Encryption

6.2.1 Encryption performance7 Déroulement

7.1 Login/Logout7.2 Metadata synchronization

7.2.1 Corrupted configurations7.3 Data states7.4 Tracker data

7.4.1 Tracker data download7.4.2 Tracker data search7.4.3 Tracker data write7.4.4 Tracker data upload7.4.5 Tracker data: reserved values7.4.6 Tracker data: relationships

7.5 Aggregated data7.5.1 Aggregated data download7.5.2 Aggregated data write7.5.3 Aggregated data upload7.5.4 DataSet instances

7.6 Dealing with FileResources7.6.1 File resources module7.6.2 File resizer helper7.6.3 File resource directory helper

8 Paramètres8.1 Settings app

9 Error management10 SMS module

10.1 SMS version10.2 ConfigCase10.3 SmsSubmitCase10.4 QrCodeCase

11 Object style11.1 Icon11.2 Color

Table des matières Applicable to version 1.3.1

3

Page 4: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

12 DHIS2 version compatibility strategy12.1 Example: minor change12.2 Example: major change

13 Direct database interaction14 Program rule engine15 Program indicator engine16 Validation rule engine17 Debugging18 Known issues

18.1 Data set completion

Table des matières Applicable to version 1.3.1

4

Page 5: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

1 À propos de ce guide

La documentation du DHIS 2 est le fruit d’un effort collectif de la part de l’équipe dedéveloppement et des utilisateurs. Ce guide se veut complet, mais il se peut que certainesfonctionnalités y soient omises ou qu’elles nécessitent encore une documentation approfondie.Cette section présente certaines des conventions utilisées dans l’ensemble du document.

DHIS2 est une application fonctionnant dans un navigateur. Dans la plupart des cas, desimpressions d’écran ont été incluse pour une meilleure compréhension. Des raccourcis versdiverses fonctionnalités sont affichés comme par exemple Element de données > Grouped’éléments de données. Le symbole “>” indique que vous devez cliquer sur Element de donnéeset ensuite sur Groupe d’éléments de données

Différents styles de texte ont été utilisés pour mettre en avant des parties importantes ou destypes particuliers de texte, tels que le code source. Chacune des conventions utilisées dans ledocument est expliquée ci-dessous.

Note

A note contains additional information which should be considered or areference to more information which may be helpful.

Tip

A tip can be a useful piece of advice, such as how to perform aparticular task more efficiently.

Important

Important information should not be ignored, and usually indicatessomething which is required by the application.

Caution

Information contained in these sections should be carefully considered,and if not heeded, could result in unexpected results in analysis,performance, or functionality.

Warning

Information contained in these sections, if not heeded, could result inpermanent data loss or affect the overall usability of the system.

Complete

Information contained in these sections, will indicate that these areissues that have been fully implemented.

Incomplete

Information contained in these sections, will indicate that these areissues that are not implemented and will be ignored.

1 À propos de ce guide Applicable to version 1.3.1

5

Page 6: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

Not_applicable

Information contained in these sections, will indicate that these areissues not applicable.

Work_in_progress

Information contained in these sections, will indicate that these areissues or features not completely implemented or with unexpectedbehaviour already reported.

Les programmes répertoriés contiennent généralement du code informatique

Ils sont affichés sur un fond sombre et avec une police distincte

Les commandes sont affichées en gras et représentent une commande àexécuter sur le système d'exploitation ou dans la base de données.

Les liens vers des sites web externes ou les références croisées seront affichés en bleu etsoulignés comme ceci..

1 À propos de ce guide Applicable to version 1.3.1

6

Page 7: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

2 Compatibility: SDK / core / Android

Compatibility table between DHIS2 Android SDK library, DHIS2 core and Android SDK API.

SDK DHIS2 core Android SDK

1.0.0 2.29 -> 2.33 19 - 28

1.0.1 2.29 -> 2.33 19 - 28

1.0.2 2.29 -> 2.33 19 - 28

1.0.3 2.29 -> 2.33 19 - 28

1.1.0 2.29 -> 2.34 19 - 28

1.1.1 2.29 -> 2.34 19 - 28

1.1.2 2.29 -> 2.34 19 - 28

1.2.0 2.29 -> 2.34 19 - 28

1.2.1 2.29 -> 2.34 19 - 28

1.3.0 2.29 -> 2.35 19 - 29

1.3.1 2.29 -> 2.35 19 - 29

2 Compatibility: SDK / core / Android Applicable to version 1.3.1

7

Page 8: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

3 Aperçu

DHIS2 Android SDK is a library that abstracts the complexity of interacting with DHIS2 web api. Itaims to be an starting point to build Android apps for DHIS2, covering some tasks that anyAndroid app should implement, like metadata and data synchronization.

Main goals:

Abstract DHIS2 web api. There is no need to perform api queries against the server. TheSDK includes methods to interact with the web api.Work offline. It implements a simplified version of DHIS2 model that is persisted in a localdatabase (SQLite). It ensures that all the metadata required to perform data entry tasks isavailable at any time to build the data entry forms. Data is saved locally and uploaded tothe server when connection is available.Ensure DHIS2 compatibility. It encapsulates the changes between DHIS2 versions so theapp does not have to care about them. In case the SDK introduces some changes toaccommodate a new DHIS2 version, the app can safely detect these changes at compile-time.

3.1 Technology overview

The SDK is written in Java 8 using the reduced subset of features allowed in the minimumAndroid API version. The SDK uses some Android-specific components, such as libraries to createpaged list (LiveData, PagedList) or to access to file system. For this reason, currently the SDK isonly runnable in an Android environment.

It uses RxJava to facilitate the asynchronous treatment of some methods. Although it is optional,we recommend this approach to ensure non-blocking calls.

Other libraries internally used by the SDK are: Dagger for dependency injection, Jackson for JSONparsing, Retrofit and OkHttpClient for API communication or SQLBrite for DB migrations.

3 Aperçu 3.1 Technology overview

8

Page 9: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

4 Mise en route

4.1 Installation

Include dependency in build.gradle.

dependencies {

implementation "org.hisp.dhis:android-core:1.3.1"

...

}

Additionally, you need to include this repository in your root gradle file if it is not already there:

allprojects {

repositories {

...

maven { url 'https://jitpack.io' }

}

}

4.2 D2 initialization

In order to start using the SDK, the first step is to initialize a D2 object. The helper class D2Manager offers static methods to setup and initialize the D2 instance. Also, it ensures that D2is a singleton across the application.

The minimum configuration that needs to be passed to the D2Manager is the following:

Using the configuration you can instantiate D2.

Once the Single is completed, you can access D2 with the following method:

If you are not using RxJava, you can instantiate D2 in a blocking way:

The object D2Configuration has a lot of fields to configure the behavior of the SDK.

Attribut Obligatoire Description Default

context vrai Application context -

D2Configuration configuration = D2Configuration.builder()

.context(context)

.build();

Single<D2> d2Single = D2Manager.instantiateD2(configuration);

D2 d2 = D2Manager.getD2();

D2 d2 = D2Manager.blockingInstantiateD2(configuration);

4 Mise en route 4.1 Installation

9

Page 10: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

Attribut Obligatoire Description Default

appName false Use to create the “user-agent” header

FromAndroidManifest

appVersion false Use to create the “user-agent” header

FromAndroidManifest

readTimeoutInSeconds false Read timeout for httpqueries

30 seconds

connectTimeoutInSeconds false Connect timeout for httpqueries

30 seconds

writeTimeoutInSeconds false Write timeout for httpqueries

30 seconds

interceptors false Interceptors forOkHttpClient

Aucun

networkInterceptors false NetworkInterceptors forOkHttpClient

Aucun

4 Mise en route 4.2 D2 initialization

10

Page 11: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

5 Modules and repositories

D2 object is the entry point to interact with the SDK. The SDK forces the D2 object to be asingleton across the application.

Modules are the layer below D2. They act as a wrapper for related functionality. A moduleincludes some related repositories and might expose some services and helpers.

Repositories act as a facade for the DB (or web API in some cases). They offer read capabilities formetadata and read/write for data.

5.1 Dealing with return types: RxJava

The SDK uses RxJava classes (Observable, Single, Completable, Flowable) as the preferred returntype for all the methods. The reasons for choosing RxJava classes are mainly two:

To facilitate the asynchronous treatment of returned objects. Most of the actions in theSDK are time consuming and must be executed in a secondary thread. These return typesforce the app to deal with this asynchronous behavior.To notify about progress. Methods like metadata or data sync might take several minutesto finish. From a user perspective, it is very helpful to have a sense of progress.

This does not mean that applications are forced to use RxJava in their code: they are only forcedto deal with the asynchronous behavior of some methods. The SDK usually exposes blockingversion of every method.

For example, the same query using RxJava and AsyncTask:

Using RxJava

Using AsyncTask

Accessing the database is time consuming and it’s recommended to do it in a separate threadusing any of the recommended methods. However, procedures that involve accessing the webAPI, like log in, metadata or data download or upload must run in a separate thread, otherwiseAndroid will throw an error.

d2.programModule().programs()

.subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.get() .subscribe(programs ->

{}); //List<Program>

new AsyncTask<Void, Void, List<Program>>() {

protected List<Program> doInBackground() {

return d2.programModule().programs().blockingGet();

}

protected void onPostExecute(List<Program> programs) {

}

}.execute();

5 Modules and repositories 5.1 Dealing with return types: RxJava

11

Page 12: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

5.2 Query building

Repositories offer a builder syntax with compile-time validation to access the resources. A typicalquery is composed of some modifiers (filter, order, nested fields) and ends with an action (get,count, getPaged,…).

5.2.1 Filters

Repositories expose the list of available filters prefixed by the keyword “by”. The list of filteroperators available for each filter is dependant on the filter value type: for example, a value type Date will offer operators like after, before, inPeriods, while a value type Boolean will offer isFalse or isTrue.

Several filters can be appended to the same query in any order. Filters are joined globally usingthe operator “AND”. This means that a query like

will return the events assigned to the orgunit “DiszpKrYNg8” AND whose eventDate is after“2019-05-05”.

5.2.2 Order by

Ordering modifiers are prefixed by the keyword “orderBy”.

Several “orderBy” modifiers can be appended to the same query. The order of the “orderBy”modifiers within the query determines the order priority. This means that a query like

will order by EventDate descendant in first place, and then by LastUpdated descendant.

5.2.3 Include nested fields

Repositories return classes that are not an exact match of database tables: they are morecomplex objects that might include some properties obtained from other tables. For example,

// Generic syntax

d2.<module>.<repository>

.[ filter | orderBy | nested fields ]

.<action>;

// An example for events

d2.eventModule().events()

.byOrganisationUnitUid().eq("DiszpKrYNg8")

.byEventDate().after(Date("2019-05-05"))

.orderByEventDate(DESC)

.withTrackedEntityDataValues()

.get();

d2.eventModule().events()

.byOrganisationUnitUid().eq("DiszpKrYNg8")

.byEventDate().after(Date("2019-05-05"))

...

d2.eventModule().events()

.orderByEventDate(DESC)

.orderByLastUpdated(DESC)

...

5 Modules and repositories 5.2 Query building

12

Page 13: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

the Event class has a property called trackedEntityDataValues that include a list ofTrackedEntityDataValues. The main reason to choose this kind of objects is to absorb thecomplexity of dealing with link tables so the app does not have to care about building linksbetween objects.

Due to performance issues, this kind of properties are not included by default: they must bequeried explicitly. In the repositories, the properties that are not included by default and need tobe queried are prefixed by the keyword “with”.

Several properties can be appended in the same query in any order. For example, a query like

will return a nested TrackedEntityType object.

5.3 Helpers

The SDK include some helpers in the package org.hisp.dhis.android.core.arch.helpers.They can be easily found in Android Studio by searching Helper in class names. They includesome helpful methods to perform common operations:

AccessHelper: related to access (sharing settings) object.CollectionsHelper: common operations to collections.CoordinateHelper, GeometryHelper: geospatial data manipulation.FileResizeHelper, FileResourceDirectoryHelper: file resource manipulation.UidsHelper: common operations to collections of objects with uid.UserHelper: operations related to user authentication.

5.4 Module list

System modules:

importModulemaintenanceModulesystemInfoModulesettingModulewipeModule

Big block modules:

metadataModuleaggregatedDataModule

Concrete modules:

categoryModuleconstantModuledataElementModuledataSetModuledataValueModuleenrollmentModuleeventModulefileResourceModuleindicatorModulelegendSetModule

d2.programModule().programs()

.withTrackedEntityType()

...

• • • • • •

• • • • •

• •

• • • • • • • • • •

5 Modules and repositories 5.3 Helpers

13

Page 14: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

noteModuleorganisationUnitModuleoptionModuleperiodModuleprogramModulerelationshipModulesmsModuletrackedEntityModuleuserModulevalidationModule

• • • • • • • • • •

5 Modules and repositories 5.4 Module list

14

Page 15: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

6 Base de données

6.1 Database scope

The SDK keeps the data of a [server, user] pair in an isolated database.

At the moment, just one [server, user] pair is supported, so logging out and logging in in withanother [server, user] pair will delete the current database and create a new one.

6.2 Encryption

As of SDK version 1.1.0, it is possible to store the data in an encrypted database. The encryptionkey is generated randomly by the SDK and kept secure.

The encryption status (if the database is encrypted or not) can be configured at server level in theandroid-settings-app. The default status is false: If the app is not installed, the database won’t beencrypted.

During the first login for a given server and user, the encryption status will be downloaded fromthe API and a database of the given type will be created.

In later logins or metadata synchronizations, the SDK will download again the encryption statusfrom the server and, if changed, will encrypt or decrypt the current database without data loss.

6.2.1 Encryption performance

Database size: the database size is approximately the same, regardless of being encryptedor not.Speed: reads and writes are on average 5 to 10% slower using an encrypted database.

6 Base de données 6.1 Database scope

15

Page 16: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

7 Déroulement

Currently, the SDK is primarily oriented to build apps that work in an offline mode. In short, theSDK maintains a local database instance that is used to get the work done locally (create forms,manage data, …). When requested by the client, this local database is synchronized with theserver.

A typical workflow would be like this:

LoginSync metadata: the SDK downloads a subset of the server metadata so it is available to beused at any time. Metadata sync is totally user-dependent (see Synchronization for moredetails)Download data: if you want to have existing data available in the device even when offline,you can download and save existing tracker and aggregated data in the device.Do the work: at this point the app is able to create the data entry forms and show someexisting data. Then the user can edit/delete/update data.Upload data: from time to time, the work done in the local database instance is sent to theserver.Sync metadata: it is recommended to sync metadata quite often to detect changes inmetadata configuration.

7.1 Login/Logout

Before interacting with the server it is required to login into the DHIS 2 instance. Currently, theSDK does only support one pair “user - server” simultaneously. That means that only one usercan be authenticated in only one server at the same time.

After a logout, the SDK keeps track of the last logged user so that it is able to differentiaterecurring and new users. It also keeps a hash of the user credentials in order to authenticate theuser even when there is no connectivity. Given that said, the login method will:

If an authenticated user already exists: throw an error.Else if Online:

Try login online: the SDK will send the username and password to the API, which willdetermine whether they are correct. If successful: - If no database exists: create newdatabase with encryption value from server. - If database for another [serverUrl,user] exists, delete it and create new database with encryption value from server.Not synced data of previously logged user will be permanently lost. - If database forthe current [serverUrl, user] pair exists, open the database and encrypt or decryptdatabase if encryption status has changed in the server.If user account has been disabled in server: delete database and throw an error.

Else if Offline: If the [serverUrl, user] pair was the last authenticated:

Try login offline: the SDK will verify that the credentials are the same as thelast provided, which were previously validated by the API.

If the [serverUrl, user] pair was not the last authenticated: throw an error

Calling module or repository methods before a successful login or after a logout will result in“Database not created” errors.

1. 2.

3.

4.

5.

6.

d2.userModule().logIn(username, password, serverUrl)

d2.userModule().logOut()

• •

◦ •

◦ ▪

7 Déroulement 7.1 Login/Logout

16

Page 17: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

Logout method removes user credentials, so a new login is required before any interaction withthe server. Metadata and data is preserved so a user is able to logout/login without losing anyinformation.

7.2 Metadata synchronization

Metadata synchronization is usually the first step after login. It fetches and persists the metadataneeded by the current user. To launch metadata synchronization we must execute:

In order to save bandwidth usage and storage space, the SDK does not synchronize all themetadata in the server but a subset. This subset is defined as the metadata required by the userin order to perform data entry tasks: render programs and datasets, execute program rules,evaluate in-line program indicators, etc.

Based on that, metadata sync includes the following elements:

Element Condition or scope

System info All

Paramètres dusystème

KeyFlag, KeyStyle

Paramètres del’utilisateur

KeyDbLocale, KeyUiLocale

Utilisateur Only authenticated user

UserRole Roles assigned to authenticated user

Authority Authorities assigned to authenticated user

Programme Programs that user has (at least) read data access to and thatare assigned to any orgunit visible by the user

RelationshipTypes All

OptionGroups Only if server is greater than 2.29

Ensemble de données DataSets that user has (at least) read data access to and that areassigned to any orgunit visible by the user

Règles de validation Validation rules associated to the dataSets

Indicateurs Indicators assigned to downloaded dataSets

OrganisationUnit OrganisationUnits in CAPTURE or SEARCH scope (descendantsincluded)

OrganisationUnitGroup Groups assigned to downloaded organisationUnits

OrganisationUnitLevel All

Constant All

SMS Module metadata Only if SMS module enabled

In the case of Programs and DataSets, metadata sync includes all the metadata related to them:stages, sections, dataElements, options, categories, etc. Those elements that are not related toany Program or DataSet are not included.

d2.metadataModule().download();

7 Déroulement 7.2 Metadata synchronization

17

Page 18: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

7.2.1 Corrupted configurations

This partial metadata synchronization may expose server-side misconfiguration issues. Forexample, a ProgramRuleVariable pointing to a DataElement that does not belong to the programanymore. Due to the use of database-level constraints, this misconfiguration will appear as aForeign Key error.

The SDK does not fail the synchronization, but it stores the errors in a table for inspection. Theseerrors can be accessed by:

7.3 Data states

Data objects have a read-only state property that indicates the current state of the object interms of synchronization with the server. This state is maintained by the SDK.

The possible states are:

SYNCED. The element is synced with the server. There are no local changes for this value.TO_POST. Data created locally that does not exist in the server yet.TO_UPDATE. Data modified locally that exists in the server.UPLOADING. Data is being uploaded. If it is modified before receiving any server response,its state is back to TO_UPDATE. When the server response arrives, its state does not changeto SYNCED, but it remains in TO_UPDATE to indicate that there are local changes.SENT_BY_SMS. Data is sent by sms and there is no server response yet. Some servers donot have the capability to send a response, so this state means that data has been sent,but we do not know if it has been correctly imported in the server or not.SYNCED_BY_SMS. Data is sent by sms and there is a successful response from the server.ERROR. Data that received an error from the server after the last upload.WARNING. Data that received a warning from the server after the last upload.

Additionally, in TrackedEntityInstance we might have:

RELATIONSHIP. This TrackedEntityInstance has been downloaded with the sole purpose offulfilling a relationship to another TEI. This RELATIONSHIP TEI only has basic information(uid, type, etc) and the list of TrackedEntityAttributes to be able to print meaningfulinformation about the relationship. Other data such as enrollments, events orrelationships are not downloaded for this TEI. Also, this TEI cannot be modified oruploaded to the server.

7.4 Tracker data

7.4.1 Tracker data download

Important

See Settings App section to know how this application can be used tocontrol synchronization parameters.

By default, the SDK only downloads TrackedEntityInstances and Events that are located in usercapture scope, but it is also possible to download TrackedEntityInstances in search scope.

The tracked entity module contains the TrackedEntityInstanceDownloader. The downloaderfollows a builder pattern which allows the download of tracked entity instances filtering by

d2.maintenanceModule().foreignKeyViolations()

• • • •

• • •

7 Déroulement 7.2.1 Corrupted configurations

18

Page 19: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

different parameters as well as defining some limits. The same behavior can be found within theevent module for events.

The downloader tracks the latest successful download in order to avoid downloading unmodifieddata. It makes use of paging with a best effort strategy: in case a page fails to be downloaded orpersisted, it is skipped and it will continue with the next pages.

This is an example of how it can be used.

Currently, it is possible to specify the next filters:

byProgramUid(). Filters by program uid and downloads the not synced objects inside theprogram.byUid(). Filters by the tracked entity instance uid and downloads a unique object. Thisfilter can be used to download the tracked entity instances found within search scope.(Only for tracked entity instances).

The downloader also allows to limit the number of downloaded objects. These limits can also becombined with each other.

limit(). Limit the maximum number of objects to download.limitByProgram(). Take the established limit and apply it to each program. The numberof objects that will be downloaded will be the one obtained by multiplying the limit set bythe number of user programs.limitByOrgunit(). Take the established limit and apply it for each organisation unit. Thenumber of objects that will be downloaded will be the one obtained by multiplying the limitset by the number of user organisation units.

The next snippet of code shows an example of the TrackedEntityInstanceDownloader usage.

Additionally, if you want the images associated to Image data values available to be downloadedin the device, you must download them. See Dealing with FileResources section for more details.

7.4.2 Tracker data search

DHIS2 has a functionality to filter TrackedEntityInstances by related properties, like attributes,organisation units, programs or enrollment dates. The Sdk provides the TrackedEntityInstanceQueryCollectionRepository with methods that allow the

d2.trackedEntityModule().trackedEntityInstanceDownloader()

.[filters]

.[limits]

.download()

d2.eventModule().eventDownloader()

.[filters]

.[limits]

.download()

• •

d2.trackedEntityModule().trackedEntityInstanceDownloader() .byProgramUid("program-

uid")

.limitByOrgunit(true)

.limitByProgram(true)

.limit(50)

.download()

7 Déroulement 7.4.2 Tracker data search

19

Page 20: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

download of tracked entity instances within the search scope. It can be found inside the trackedentity instance module.

The tracked entity instance query is a powerful tool that follows a builder pattern and allows thedownload of tracked entity instances filtering by different parameters.

The source where the TEIs are retrieved from is defined by the repository mode. These are thedifferent repository modes available:

onlineOnly(). Only TrackedEntityInstances coming from the server are returned in thelist. Internet connection is required to use this mode.offlineOnly(). Only TrackedEntityInstances coming from local database are returned inthe list.onlineFirst(). TrackedEntityInstances coming from the server are returned in firstplace. Once there are no more results online, it continues with TrackedEntityInstances inthe local database. Internet connection is required to use this mode.offlineFirst(). TrackedEntityInstances coming from local database are returned in firstplace. Once there are no more results, it continues with TrackedEntityInstances comingfrom the server. This method may speed up the initial load. Internet connection is requiredto use this mode.

This repository follows the same syntax as other repositories. Additionally, the repository offersdifferent strategies to fetch data:

byAttribute(). This method adds an attribute filter to the query. If this method is calledseveral times, conditions are appended with an AND connector. For example:

That means that the instance must have attribute uid1 with value value1 AND attribute uid2 with value value2.

byFilter(). This method adds a filter to the query. If this method is called several times,conditions are appended with an AND connector. For example:

That means that the instance must have attribute uid1 with value value1 AND attribute uid2 with value value2.

byQuery(). Search tracked entity instances with any attribute matching the query.

byProgram(). Filter by enrollment program. Only one program can be specified.

d2.trackedEntityModule().trackedEntityInstanceQuery()

.[repository mode]

.[filters]

.get()

d2.trackedEntityModule().trackedEntityInstanceQuery()

.byAttribute("uid1").eq("value1")

.byAttribute("uid2").eq("value2")

.get()

d2.trackedEntityModule().trackedEntityInstanceQuery()

.byFilter("uid1").eq("value1")

.byFilter("uid2").eq("value2")

.get()

7 Déroulement 7.4.2 Tracker data search

20

Page 21: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

byOrgUnits(). Filter by tracked entity instance organisation units. More than oneorganisation unit can be specified.

byOrgUnitMode(). Define the organisation unit mode. The possible modes are the next:

SELECTED. Specified units only.CHILDREN. Immediate children of specified units, including specified units.DESCENDANTS. All units in sub-hierarchy of specified units, including specified units.ACCESSIBLE. All organisation units accessible by the user (search scope).ALL. All units in system. Requires authority.

byProgramStartDate(). Define an enrollment start date. It only applies if a program hasbeen specified.

byProgramEndDate(). Define an enrollment end date. It only applies if a program hasbeen specified.

byTrackedEntityType(). Filter by TrackedEntityType. Only one type can be specified.

byIncludeDeleted(). Whether to include or not deleted tracked entity instances.Currently, this filter only applies to offline instances.

byStates(). Filter by sync status. Using this filter forces offline only mode.

Example:

Important

TrackedEntityInstances retrieved using this repository are not persistedin the database. It is possible to fully download them using the byUid()filter of the TrackedEntityInstanceDownloader within the trackedentity instance module.

7.4.3 Tracker data write

In general, there are two different cases to manage data creation/edition/deletion: the casewhere the object is identifiable (that is, it has an uid property) and the case where the object isnot identifiable.

Identifiable objects (TrackedEntityInstance, Enrollment, Event). These repositories have a uid()method that gives you access to edition methods for a single object. In case the object does notexist yet, it is required to create it first. A typical workflow to create/edit an object would be:

Use the CreateProjection class to add a new instance in the repository.Save the uid returned by this method.Use the uid() method with the previous uid to get access to edition methods.

And in code this would look like:

◦ ◦ ◦ ◦ ◦

d2.trackedEntityModule().trackedEntityInstanceQuery()

.byOrgUnits().eq("orgunitUid")

.byOrgUnitMode().eq(OrganisationUnitMode.DESCENDANTS)

.byProgram().eq("programUid")

.byAttribute("attributeUid").like("value")

.offlineFirst()

• • •

7 Déroulement 7.4.3 Tracker data write

21

Page 22: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

Non-identifiable objects (TrackedEntityAttributeValue, TrackedEntityDataValue). Theserepositories have a value() method that gives you access to edition methods for a single object.The parameters accepted by this method are the parameters that unambiguously identify avalue.

For example, writing a TrackedEntityDataValue would be like:

Data values of type Image involve an additional step to create/update/read the associated fileresource. More details in the Dealing with FileResources section below.

7.4.4 Tracker data upload

TrackedEntityInstance and Event repositories have an upload() method to upload Tracker dataand Event data (without registration) respectively. If the repository scope has been reduced byfilter methods, only filtered objects will be uploaded.

Data whose state is ERROR or WARNING cannot be uploaded. It is required to solve the conflictsbefore attempting a new upload: this means to do a modification in the problematic data, whichforces their state back to TO_UPDATE.

7.4.4.1 Tracker conflicts

Server response is parsed to ensure that data has been correctly uploaded to the server. In casethe server response includes import conflicts, these conflicts are stored in the database, so theapp can check them and take an action to solve them.

Conflicts linked to a TrackedEntityInstance, Enrollment or Event are automatically removed aftera successful upload of the object.

The SDK tries to identify the confliction dataElement or attribute by parsing the server response.If so, it also stores the value of the element when the conflict happened so that the applicationcan highlight the element in form when the value has not been fixed yet.

7.4.5 Tracker data: reserved values

Tracked Entity Attributes configured as unique and automatically generated are generated by theserver following a pattern defined by the user. These values can only be generated by the server,which means that we need to reserve them in advance so we can make use of them whenoperating offline.

String eventUid = d2.eventModule().events().add(

EventCreateProjection.create("enrollment", "program", "programStage", "orgUnit", "attCombo"));

d2.eventModule().events().uid(eventUid).setStatus(COMPLETED);

d2.trackedEntityModule().trackedEntityDataValues().value(eventUid, dataElementid).set(“5”);

d2.( trackedEntityModule() | eventModule() )

.[ filters ]

.upload();

d2.importModule().trackerImportConflicts()

7 Déroulement 7.4.4 Tracker data upload

22

Page 23: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

The app is responsible for reserving generated values before going offline. This can be triggeredby:

Depending on how long the app expects to be offline, it can decide the quantity of values toreserve. In case the attribute pattern is dependant on the orgunit code, the SDK will reservevalues for all the relevant orgunits. More details about the logic in Javadoc.

Reserved values can be obtained by:

7.4.6 Tracker data: relationships

Currently the SDK only supports relatinships from TEI to TEI. They accessed by using therelationships module.

Query relationships associated to a TEI.

In the same module you can create new relationships using this method:

If the related trackedEntityInstance does not exist yet and there are attribute values that must beinherited, you can use the following method to inherit attribute values from one TEI to another inthe context of a certain program. Only those attribute marked as inherit will be inherited.

7.5 Aggregated data

7.5.1 Aggregated data download

Important

See Settings App section to know how this application can be used tocontrol synchronization parameters.

// Reserve values for all the unique and automatically generated trackedEntityAttributes.

d2.trackedEntityModule().reservedValueManager().downloadAllReservedValues(numValuesToFillUp)

// Reserve values for a particular trackedEntityAttribute.

d2.trackedEntityModule().reservedValueManager().downloadReservedValues("attributeUid", numValuesToFillUp)

d2.trackedEntityModule().reservedValueManager().getValue("attributeUid", "orgunitUid")

d2.relationshipModule().relationships().getByItem(

RelationshipHelper.teiItem("trackedEntityInstanceUid")

)

Relationship relationship = RelationshipHelper.teiToTeiRelationship("fromTEIUid", "toTEIUid", "relationshipTypeUid");

d2.relationshipModule().relationships().add(relationship);

d2.trackedEntityModule().trackedEntityInstanceService() .inheritAttributes("fromTeiUid",

"toTeiUid", "programUid");

7 Déroulement 7.4.6 Tracker data: relationships

23

Page 24: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

By default, the SDK downloads aggregated data values, dataset complete registration values and approvals corresponding to:

DataSets: all available dataSets (those the user has at least read data access to).

OrganisationUnits: capture scope.

Periods: all available periods, which means at least:

Days: last 60 days.Weeks: last 13 weeks (including starting day variants).Biweekly: last 13 bi-weeks.Monthly: last 12 months.Bimonthly: last 6 bi-months.Quarters: last 5 quarters.Sixmonthly: last 5 six-months (starting in January and April).Yearly: last 5 years (including financial year variants).

In addition, if any dataset allows data entry for future periods, the Sdk will download thedata for those open periods and store them.

The Sdk also keeps track of the latest successful download in order to avoid downloadingunmodified server data.

In the download of data approvals, workflow and attribute option combination identifiers will beconsidered in addition to the organisation units and periods. The different possible states fordata approval are:

UNAPPROVABLE. Data approval does not apply to this selection. (Data is neither approvednor unapproved).UNAPPROVED_WAITING. Data could be approved for this selection, but is waiting for somelower-level approval before it is ready to be approved.UNAPPROVED_ELSEWHERE. Data is unapproved and is waiting for approval somewhere else(can not be approved here).UNAPPROVED_READY. Data is unapproved, and is ready to be approved for this selection.UNAPPROVED_ABOVE. Data is unapproved above.APPROVED_HERE. Data is approved, and was approved here (so could be unapprovedhere).APPROVED_ELSEWHERE. Data is approved, but was not approved here (so cannot beunapproved here).APPROVED_ABOVE. Data is approved above.ACCEPTED_HERE. Data is approved and accepted here (so could be unapproved here).ACCEPTED_ELSEWHERE. Data is approved and accepted, but elsewhere.

Data approvals are downloaded only for versions greater than 2.29.

7.5.2 Aggregated data write

7.5.2.1 Periods

In order to write data values or data set complete registrations, it’s mandatory to provide aperiod id. Periods are stored in a table in the database and the provided period ids must bealready present in that table, otherwise, a Foreign Key error will be thrown. To prevent that

d2.aggregatedModule().data().download()

◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦

• • •

• • •

7 Déroulement 7.5.2 Aggregated data write

24

Page 25: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

situation, the PeriodHelper is exposed inside the PeriodModule. Before adding aggregateddata related to a dataSet, the following method must be called:

This will ensure that:

The app will pick one of the given periods, preventing malformed or wrong periods.The app will only be able to pick the future periods defined by the field DataSet.openFuturePeriods.The app will only be able to pick the past periods defined based on the limits declared onthe section Aggregated Data Download.

7.5.2.2 Data value

DataValueCollectionRepository has a value() method that gives access to edition methods. Theparameters accepted by this method are the parameters that unambiguously identify a value.

7.5.2.3 Data set complete registration

The Sdk provides within the data set module a collection repository for data set completeregistrations. This repository contains methods to add new completions and delete them.

To add a new data set complete registration is available an add() method:

In order to remove them from the database, the repository has a value() method that givesaccess to deletion methods (delete() and deleteIfExist()). The parameters accepted bythis method are the parameters that unambiguously identify the data set complete registration.

7.5.3 Aggregated data upload

DataValueCollectionRepository has an upload() method to upload aggregated data values.

Single<List<Period>> periods = d2.periodModule().periodHelper().getPeriodsForDataSet("dataSetUid");

1. 2.

3.

DataValueObjectRepository valueRepository = d2.dataValueModule().dataValues()

.value("periodId", "orgunitId", "dataElementId", "categoryOptionComboId", "attributeOptionComboId");

valueRepository.set("value")

d2.dataSetModule().dataSetCompleteRegistrations()

.add(dataSetCompleteRegistration);

d2.dataSetModule().dataSetCompleteRegistrations() .value("periodId",

"orgunitId", "dataSetUid","attributeOptionCombo")

.delete()

d2.dataValueModule().dataValues().upload();

7 Déroulement 7.5.3 Aggregated data upload

25

Page 26: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

7.5.4 DataSet instances

A DataSetInstance in the SDK is a handy representation of the existing aggregated data. ADataSetInstance represents a unique combination of DataSet - Period - Orgunit -AttributeOptionCombo and includes extra information like sync state, value count ordisplayName for some properties.

If you only need a high level overview of the aggregated data status, you can use the repository DataSetInstanceSummary. It accepts the same filters and returns a count of DataSetInstance for each combination.

7.6 Dealing with FileResources

The SDK offers a module (the FileResourceModule) and two helpers (the FileResourceDirectoryHelper and FileResizerHelper) that allow to work with files.

7.6.1 File resources module

This module contains methods to download the file resources associated with the downloadeddata and the file resources collection repository of the database.

File resources download. The download() method will search for the tracked entityattribute values and tracked entity data values whose tracked entity attribute type anddata element type are of the image type and whose file resource has not been previouslydownloaded and the method will download the file resources associated.

After downloading the files, you can obtain the different file resources downloadedthrough the repository.

File resource collection repository. Through this repository it is possible to request files,save new ones and upload them to the server.

Get. It behaves in a similar fashion to any other Sdk repository. It allows to getcollections by applying different filters if desired.

Add. To save a file you have to add it using the add() method of the repository byproviding an object of type File. The add() method will return the uid that was

d2.dataSetModule().dataSetInstances()

.[ filters ]

.get()

// For example

d2.dataSetModule().dataSetInstances()

.byDataSetUid().eq("datasetUid")

.byOrganisationUnitUid().eq("orgunitUid") .byPeriod().in("201901",

"201902")

.get();

d2.fileResourceModule().download();

d2.fileResourceModule().fileResources()

.[ filters ]

.get()

7 Déroulement 7.5.4 DataSet instances

26

Page 27: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

generated when adding the file. This uid should be used to update the tracked entityattribute value or the tracked entity data value associated with the file resource.

Upload. Calling the upload() method will trigger a series of successive calls inwhich all non-synchronized files will be sent to the server. After each upload, theserver response will be processed. The server will provide a new uid to the fileresource and the Sdk will automatically rename the file and update the FileResource object and the tracked entity attribute values or tracked entity datavalues associated with it.

7.6.2 File resizer helper

The Sdk provides a helper to resize image files (FileResizerHelper). This helper contains a resizeFile() method that accepts the file you want to reduce and the dimension to which youwant to reduce it.

The possible dimensions are in the following table.

Small Medium Large

256px 512px 1024px

The helper takes the file, measures the height and width of the image, determines which of thetwo sides is larger and reduces the largest of the sides to the given dimension and the other sideis scaled to its proportional size. Image scaling will always keep the proportions.

In the event that the last image is smaller than the dimension to which you want to resize it, thesame file will be returned without being modified.

The resizeFile() method will return a new file located in the same parent directory of the fileto be resized under the name resized-DIMENSION- + the name of the file without resizing.

7.6.3 File resource directory helper

The FileResourceDirectoryHelper helper class provides two methods.

getFileResourceDirectory(). This method returns a File object whose path points tothe sdk_resources directory where the Sdk will save the files associated with the fileresources.

getFileCacheResourceDirectory(). This method returns a File object whose pathpoints to the sdk_cache_resources directory. This should be the place where volatilefiles are stored, such as camera photos or images to be resized. Since the directory iscontained in the cache directory, Android may auto-delete the files in the cache directoryonce the system is about to run out of memory. Third party applications can also deletefiles from the cache directory. Even the user can manually clear the cache from Settings.However, the fact that the cache can be cleared in the methods explained above shouldnot mean that the cache will automatically get cleared; therefore, the cache will need to betidied up from time to time proactively.

d2.fileResourceModule().fileResources() .add(file); // Single<String> The

fileResource uid

d2.fileResourceModule().fileResources()

.upload()

7 Déroulement 7.6.2 File resizer helper

27

Page 28: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

8 Paramètres

Settings are downloaded on every metadata synchronization. There are different kinds ofsettings:

System settings: system-wide properties such as flag or style.User settings: user specific settings such as keyDbLocale or keyUiLocale.Settings app: these settings offer additional control over the behavior of the application.More about this in the next section.

8.1 Settings app

The DHIS2 instance might include a web application called “Android Settings” that allow to haveremote control over certain parameters in the application. The installation and configuration ofthis application is optional.

This SDK downloads this configuration in every metadata synchronization and persist it in thedatabase. Some of these parameters are automatically consumed by the SDK (in bold).

General:

Metadata/data sync frequency: this value must be consumed by the application and usedto trigger the synchronization in the SDK.Mobile configuration: gateway number, sender number. They must be consumed by theapplication and used to configure the SMS module in the SDK.Reserved values: number of attribute values to reserve.Encrypt database: whether or not to encrypt local database.

Programs: this section controls the program data synchronization parameters. It has a section todefine global or default parameters to be used in the synchronization of all programs.Additionally it allows to set specific settings for particular programs. All these parameters areconsumed by the SDK and used in the synchronization process.

DataSets: this section controls the aggregated data synchronization parameters. It has a sectionto define global or default parameters to be used in the synchronization of all dataSets.Additionally it allows to set specific setting for particular dataSets. All these parameters areconsumed by the SDK and used in the synchronization process.

Although these parameters are automatically consumed by the SDK, the application mightoverride some of those values in the synchronization process. For example, it might define adifferent TEI or event limit or a different download strategy (limitByOrgUnit, limitByProgram).

d2.settingModule()

• • •

• •

// General settings

d2.settingModule().generalSetting().get();

// Program settings

d2.settingModule().programSetting().get();

// DataSet settings

d2.settingModule().dataSetSetting().get();

8 Paramètres 8.1 Settings app

28

Page 29: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

9 Error management

Errors that happen in the context of the SDK are wrapped in a type of exception: D2Error, withthe following fields:

Attribut Type Facultatif Description

errorComponent D2ErrorComponent vrai Source of the error: Database,SDK or Server.

errorCode D2ErrorCode vrai SDK-defined unique error code.

errorDescription Chaîne vrai Description of the error inenglish (technical details, just forlogs and debugging).

httpErrorCode Integer false If caused by HTTP request, HTTPerror code.

originalException Exception false Original Java Exception causingthe error, if any.

Any operation requested to the SDK can throw an error.

For operations returning RxJava objects, the errors can be extracted in the following way:

For blocking operations, it is also possible to retrieve a D2Error. The errors can beextracted by caching them as shown in the following code snippet:

D2Errors are persisted in the Database when they occur, so they can be analyzed afterwardsand diagnose possible problems. They can be accessed through it’s own repository:

d2.userModule().logIn(username, password, url)

.subscribe(

user -> { },

error -> { if (error instanceof

D2Error) {

D2Error d2Error = (D2Error) error; Log.e("LOGIN", d2Error.errorComponent() + " " +

d2Error.httpErrorCode() + " " + d2Error.errorCode());

}

}

);

try {

d2.userModule().blockingLogIn(username, password, url);

} catch (Exception e) {

if (e.getCause() instanceof D2Error) {

D2Error d2Error = (D2Error) e.getCause();

Log.e("LOGIN", d2Error.errorComponent() + " " + d2Error.httpErrorCode() + " " + d2Error.errorCode());

}

}

9 Error management 8.1 Settings app

29

Page 30: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

The SDK team is now working together with the core team in order to provide a full list ofcommon error codes, but it’s still a work in progress.

d2.maintenanceModule().d2Errors()

.byD2ErrorComponent().eq(D2ErrorComponent.Server)

.get();

9 Error management 8.1 Settings app

30

Page 31: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

10 SMS module

SMS Module can be used as a fallback method to upload data when an Internet connection is notavailable. It requires an additional setup in the server: an SMS gateway must be configured in theserver to be able to receive SMS; optionally, the server might have the capability to send SMSback to the clients with the response.

Depending on the mobile provider, sending SMS might imply an extra cost. For this reason, SMSModule is only intended for granular data upload. It is not used for metadata download or bulkdata download/upload. Additionally, the data is compressed by using the SMS compressionlibrary so the content can fit in a lower number of messages. This library is shared with thebackend.

For testing purposes you can use the DHIS2 Android SMS Gateway.

In the SDK, the SMS module can be accessed from D2.

This module is disabled by default and it must be explicitly enabled and configured. It includesthree components that give access to module features.

ConfigCase: it is used to set initial data that is common for all sms sending tasks likegateway numbers, timeout, execute downloading of metadata ids object.SmsSubmitCase. it is used to convert the DHIS2 data that will be sent by the Sdk, to send itby SMS and to check the progress of the submission and his result.QrCodeCase: it is used to convert DHIS2 data to String. This String is a compressedrepresentation of the DHIS2 data. This is useful to avoid send large content on SMSes.

A typical workflow to use the SMS Module would be like:

Enable the SMS module.Sync metadata. The SMS Module downloads additional metadata from the server, so thisstep must be done while Internet connection is available and after the module is enabled.Send data using SMS Module.

This a code example of a typical workflow (it used blocking methods for code simplicity):

d2.smsModule()

• •

// Enable SMS Module

d2.smsModule().configCase().setModuleEnabled(true).blockingAwait();

// Sync SMS Module metadata using SMS Module

d2.smsModule().configCase().refreshMetadataIds().blockingAwait();// or using

metadata module

d2.metadataModule().blockingDownload();

// Configure, at least, the gateway number. See ConfigCase for more parameters

d2.smsModule().configCase().setGatewayNumber("gateway-number").blockingAwait();

// Send data. For example a tracker event:

SmsSubmitCase case = d2.smsModule().smsSubmitCase();

10 SMS module 8.1 Settings app

31

Page 32: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

Important

The app is responsible for asking the user for permissions(READ_PHONE_STATE, SEND_SMS, READ_SMS, RECEIVE_SMS).Otherwise, SMS module will fail.

10.1 SMS version

SMSs are sent in a compressed format from/to the server. This task is done by the SMSCompression library, which is responsible for doing the conversion between the plain text andthe compressed format.

The SDK includes the latest available version of the compression library, but there is noguarantee that the server is using it as well. For this reason, it is required to check the serverversion in order to enable/disable some functionalities. The SMS version in the server can bechecked by:

Overview of versions - features:

Version 1:

Aggregated data.Tracker / event data, but there are some known bugs. We recommend not to enabletracker SMS sync in version 1.

Version 2:

Add support for empty lists.Add support for geometry in events (POINT).Add missing properties in events (event data, due date) and enrollments (execution date,incident date).Add support for sending enrollment + events in the same SMS submit case.

For more information, please check SMS compression repository.

10.2 ConfigCase

Use this case to configure the SMS Module before using it. It is required, at least, to:

Enable the module.Set a gateway number.Download the metadata ids.

There are other optional parameters to control if the SDK should wait a response from the serveror not and the response timeout. Also, it is possible to specify the sender number so messagesreceived from other senders are ignored.

Integer numSMSs = case.convertTrackerEvent("event-uid").blockingGet();

case.send().blockingSubscribe();

d2.systemInfoModule().versionManager().getSmsVersion()

• •

• • •

d2.smsModule().configCase()

• • •

10 SMS module 10.1 SMS version

32

Page 33: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

10.3 SmsSubmitCase

Use this case to create a new submission and send it. Submission cases are not reusable and canonly be sent once. To create a new submission case call the method:

A submission involve the following steps:

Specify the data to submit. This means to call a method like convert*().Send the message.Optionally check for confirmation SMS.

As an example, sending a tracker event will be like:

The next methods can be used to set the DHIS2 data to send:

convertSimpleEvent(). To set a simple event.convertTrackerEvent(). To set a tracker event.convertEnrollment(). To set an enrollment.convertDataSet(). To set a data set.convertRelationship(). To set a relationship.convertDeletion(). To delete an event.

The methods above returns a single with the number of messages that the items takes up. Anexample of the use of these methods is shown in the next snippet.

To send the data converted earlier the Sdk provides a send() method that returns a stream ofthe current states. Also it is possible to get the submission id by calling the method getSubmissionId().

It is also possible to wait for the SMS result by calling the checkConfirmationSms() method. Itreturns a Completable object where completion means that the SMS was received successfully.In case that the result cannot be found, it returns an error. The date accepted is the minimumdate for which confirmation is going to be checked, this is used to skip old messages that mayhave the same submission id.

SmsSubmitCase case = d2.smsModule().smsSubmitCase();

• • •

SmsSubmitCase case = d2.smsModule().smsSubmitCase();

Integer numSMSs = case.convertTrackerEvent("event-uid").blockingGet();

case.send().blockingSubscribe();

• • • • • •

Single<Integer> convertTask = d2.smsModule().smsSubmitCase()

.convertEnrollment("enrollment_uid")

d2.smsModule().smsSubmitCase().send()

d2.smsModule().smsSubmitCase().checkConfirmationSms(new Date());

10 SMS module 10.3 SmsSubmitCase

33

Page 34: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

These methods can fail and return a PreconditionFailed object if some conditions are notsatisfied. The preconditions errors are:

NO_NETWORK.NO_CHECK_NETWORK_PERMISSION.NO_RECEIVE_SMS_PERMISSION.NO_SEND_SMS_PERMISSION.NO_GATEWAY_NUMBER_SET.NO_USER_LOGGED_IN.NO_METADATA_DOWNLOADED.SMS_MODULE_DISABLED.

10.4 QrCodeCase

Use this method to obtain a compressed representation of the data.

QrCodeCase can convert the next type of DHIS2 objects:

Simple events. Using the generateSimpleEventCode() method and passing an eventuid.Tracker events. Using the generateTrackerEventCode() method and passing an eventuid.Enrollments. Using the generateEnrollmentCode() method and passing an enrollmentuid.Relationships. Using the generateRelationshipCode() method and passing arelationship uid.Data sets. Using the generateDataSetCode() method and passing a data set uid, anorganisation unit uid, an attribute option combo and a period id.

Also it is possible to get compressed strings that can be used to delete events:

Deletions. Using the generateDeletionCode() method and passing the uid of the event.

These methods returns a Single with the compressed data. The next code snippet shows anexample of how it can be used.

• • • • • • • •

d2.smsModule().qrCodeCase()

Single<String> convertTask = d2.smsModule().qrCodeCase().generateEnrollmentCode(enrollmentUid);

10 SMS module 10.4 QrCodeCase

34

Page 35: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

11 Object style

Some elements include a property called “style” that defines an icon and a color. This visualinformation is very useful to quickly navigate through the application. Some typical use cases:

Distinguish different programs and trackedEntityTypes in a program list.In data entry forms with an optionSet, show the options with icons and colors instead ofnames.Different programStages within a program.

This property is optional and it is not defined in most of the cases. An object style might have anicon, or a color, or both.

11.1 Icon

The set of icons used in DHIS2 are included in the SDK. They are located within the resources, inthe “drawable” folder. Currently they are predefined and cannot be customized.

11.2 Color

It contains the Hex value for the color. It can be used to customize the background, text color,line headings, etc.

• •

// Illustrative code to get the resource id

if (program.style().icon() != null) {

String iconName = program.style().icon();

int resourceId = getResources().getIdentifier(iconName, "drawable", getPackageName());

}

program.style().color(); // For example #9C33FF

11 Object style 11.1 Icon

35

Page 36: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

12 DHIS2 version compatibility strategy

The SDK guarantees compatibility with the latest three DHIS 2 releases (see Compatibility). Incase the SDK is still compatible with previous DHIS2 versions and no major issues have beendetected, compatibility could be extended to previous versions.

In order to avoid accidental login into unsupported DHIS 2 instances, the SDK blocks connectionsto version that are not supported yet or that have been deprecated.

Regarding data model and compatibility, the main approach is to extend the data model to beable to support all the DHIS 2 versions. It usually happens that new DHIS 2 versions introduceextra functionality and do not remove existing one, so supporting a new DHIS 2 version usuallymeans to use the latest data model.

As a general rule the SDK tries to avoid breaking changes in its API and new features are optionalto the user. This rule is followed as much as possible, but there are cases where supporting oldand new APIs to avoid breaking has a very high cost. In this scenario the SDK might introducebreaking changes to be compatible with the new DHIS 2 version.

Here you can find a few examples of changes in the SDK and the effect in the app.

12.1 Example: minor change

Until version 2.30, Program model had a boolean attribute called “captureCoordinates”. Thisattribute indicates if coordinates (point) must be stored in that program. As of 2.30, this attributewas replaced by “featureType” with 4 possible values: NONE, POINT, POLYGON,MULTI_POLYGON.

Changes in the SDK:

As of 2.30, the SDK uses the attribute “featureType”. If the server version is lower than 2.30, theSDK maps the “captureCoordinates” value to:

false - NONEtrue - POINT

Changes in the app:

The app is now force to use “featureType”. Modifications in the code are quite straightforward.

12.2 Example: major change

As of 2.30, Relationship model suffered from a deep refactor in order to allow relationshipsbetween event, enrollment and trackedEntityInstances. The SDK adopted the model for 2.30 andexposes this model to the app. When interacting with the API, the SDK translates between bothmodels internally.

Changes in the app:

This change implies that the app must adopt a different model and changes are not sostraightforward.

• •

12 DHIS2 version compatibility strategy 12.1 Example: minor change

36

Page 37: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

13 Direct database interaction

Repository methods cover most of the needs of the application. But in some cases theapplication might want to interact directly with the database.

The SDK exposes a DatabaseAdapter object to execute raw statements in the database. Also, SDKmodel classes include helper methods to create instances from a Cursor.

For example, read the list of constants using repositories and interacting directly with thedatabase.

TableInfo classes include some useful information about table structure, like table and columnnames.

// Using repositories

d2.constantModule().constants().blockingGet() // List<Constant>

// Direct database interaction

String query = "SELECT * FROM " + ConstantTableInfo.TABLE_INFO.name();

try (Cursor cursor = Sdk.d2().databaseAdapter().rawQuery(query)) {

List<Constant> constantList = new ArrayList<>();

if (cursor.getCount() > 0) {

cursor.moveToFirst();

do {

collection.add(Constant.create(cursor));

}while(cursor.moveToNext());

} return

constantList; // List<Constant>

}

13 Direct database interaction 12.2 Example: major change

37

Page 38: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

14 Program rule engine

The program rule engine is not provided within the SDK. It is implemented in a separate library,so the same code is used by backend and android apps.

More info dhis2-rule-engine.

14 Program rule engine 12.2 Example: major change

38

Page 39: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

15 Program indicator engine

The SDK includes its own Program Indicator engine for the evaluation of in-line ProgramIndicators. These kind of indicators are evaluated within the context of an enrollment or a singleevent and they are usually placed in the data entry form offering additional information to thedata encoder. This means that, even though they are regular Program Indicators and can becalculated across enrollments, they have provide useful information within a single enrollment.

A good example, “Average time between visits”.

A bad example, “Number of active TEIs”: it would always be 1.

In order to trigger the Program Indicator Engine, just execute:

Either enrollment-uid or event-uid must be non-null.

Compatibility table:

Common functions Supported

si Oui

isNull Oui

isNotNull Oui

firstNonNull Oui

greatest Oui

least Oui

Function (d2:)(doc) Supported

addDays Oui

ceil Oui

concatenate Oui

condition Oui

count Oui

countIfCondition Oui

countIfValue Oui

countIfZeroPos No doc

daysBetween Oui

floor Oui

hasUserRole No doc

hasValue Oui

inOrgUnitGroup No doc

left Oui

length Oui

d2.programModule()

.programIndicatorEngine() .getProgramIndicatorValue(<enrollment-uid>, <event-uid>, <program-

indicator-uid>);

15 Program indicator engine 12.2 Example: major change

39

Page 40: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

Function (d2:)(doc) Supported

minutesBetween Oui

modulus Oui

monthsBetween Oui

oizp Oui

relationshipCount Non

droite Oui

round Oui

split Oui

substring Oui

validatePatten Oui

weeksBetween Oui

yearsBetween Oui

zing Oui

zpvc Oui

Variables (doc) Supported

completed_date Oui

creation_date Oui

current_date Oui

due_date Oui

enrollment_count Oui

enrollment_date Oui

enrollment_status Oui

event_count Oui

event_date Oui

incident_date Oui

organisationunit_count N/A

program_stage_id Non

program_stage_name Non

reporting_period_end N/A

reporting_period_start N/A

sync_date Non

tei_count N/A

value_count Oui

zero_pos_value_count Oui

Other components:

Component Supported

PS_EVENTDATE Oui

15 Program indicator engine 12.2 Example: major change

40

Page 41: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

16 Validation rule engine

Validation rules associated to a particular dataSet can be evaluated using the validation rulemodule. It only suppports the evaluation of validation rules in the context of a data entry form,i.e, validation rules that use data values contained in a particular combination of dataSet, period,organisationUnit and attributeOptionCombo.

Important

Currently it is not possible to evaluate validation rules acrross differentdataSets, periods, organisationUnits or attributeOptionCombos.

It returns a validation result containing the list of violations. Each violation includes helpfulmethods to get a human-readable representation of the conflict.

d2.validationModule()

.validationEngine() .validate(<dataSet-uid>, <period-id>, <organisation-unit-uid>, <attribute-option-

combo-uid>);

16 Validation rule engine 12.2 Example: major change

41

Page 42: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

17 Debugging

Besides the regular debugging tools in AndroidStudio, the library Stetho allows the use ofChrome Developer Tools for debugging network traffic and explore the database.

Setup up Stetho by adding the following dependencies in your gradle file:

dependencies {

implementation 'com.facebook.stetho:stetho:1.5.0'

implementation 'com.facebook.stetho:stetho-okhttp3:1.5.0'

}

Then add a network interceptor in D2Configuration object:

Finally enable initialize Stetho in the Application class:

At this point you should be able to debug the app/sdk by using Chrome Inspector Tools:

Run a test in debug mode and set a breakpoint.In Chrome Browser open the device inspector.Select the remote target and click on Inspect. A new windows will appear showing theChrome developer tools.Explore database in “Resources > Web SQL”.Explore network traffic in “Network”.

D2Configuration.builder()

... .networkInterceptors(Collections.singletonList(new

StethoInterceptor()))

...

.build();

if (DEBUG) {

Stetho.initializeWithDefaults(this);

}

• • •

• •

17 Debugging 12.2 Example: major change

42

Page 43: Guide DHIS 2 du développeur d’Android SDK2 Compatibility: SDK / core / Android 3 Aperçu 3.1 Technology overview 4 Getting started 4.1 Installation 4.2 D2 initialization 5 Modules

18 Known issues

18.1 Data set completion

In DHIS2 version 2.33.0 and 2.33.1, if a dataset is mark as uncompleted in the server, thisvalue is not updated in the SDK. In those versions the API did not expose enoughinformation to know if the status was complete or uncomplete.

18 Known issues 18.1 Data set completion

43