C3PRO uses the HAPI FHIR library and ResearchStack in an attempt to bring the C3-PRO functionality to Android.
Combining 🔥 FHIR and ResearchStack, usually for data storage into i2b2, this framework allows you to use
FHIR Questionnaire
resources directly with a ResearchStack ViewTaskActivity
and will return FHIR QuestionnaireResponse
that
you can send to your server.
This is a sample application, demonstrating how to use the C3PRO Android Framework. It is available here as a Android / Gradle Project. It can be inported in Android Studio by clicking "VCS" -> "Check out from Version Control" -> GitHub. The few things that need to be set up in order for a project to run with C3PRO are marked as TODOs. In this project they are all set up and should work out of the box.
To set up a new project using the C3PRO framework, the library is available on jCenter and can simply be added as a dependency:
dependencies {
compile ('ch.usz.c3pro:c3-pro-android-framework:0.1.2'){
exclude module: 'javax.servlet-api'
exclude module: 'hapi-fhir-base'
}
}
Some packages of third party dependencies need to be excluded to avoid duplicate class names.
#####The setup
The app has a class called C3PROApplication which is a subclass of Application
and is set as the main application in the AndroidManifest.
It seems that for now, multidex is needed to accomodate the large number of references in the library's dependencies. So it is necessary to enable Multidex in the application and the gradle build file.
Most setup methods are found in the onCreate() method of the C3PROApplication class.
The C3PRO class is initialized with the application's context and a FHIR Server URL.
There are also some ResearchStack settings. More details about that can be found on the ResearchStack website.
The Application
file should look something like this:
public class C3PROApplication extends Application {
/* with HAPI it seemed necessary to enable multidex to accomodate the large
number of operations provided by the package. It seems to work without it now. Leaving it here
for now just in case.*/
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
@Override
public void onCreate() {
super.onCreate();
/**
* Initialize C3PRO:
* C3PRO will provide you with a FhirContext. This Object is expensive and you should
* only have one instance in your app. Therefore, C3PRO will keep it as a singleton.
* Access it by calling C3PRO.getFhirContext();
* <p />
* If you provide a context (your application) and an URL, C3PRO
* will create a DataQueue for you to create and read Resources from your server in a
* background thread.
* */
C3PRO.init(this, "http://fhirtest.uhn.ca/baseDstu3");
// ResearchStack: Customize your pin code preferences
PinCodeConfig pinCodeConfig = new PinCodeConfig(); // default pin config (4-digit, 1 min lockout)
// ResearchStack: Customize encryption preferences
EncryptionProvider encryptionProvider = new UnencryptedProvider(); // No pin, no encryption
// ResearchStack: If you have special file handling needs, implement FileAccess
FileAccess fileAccess = new SimpleFileAccess();
// ResearchStack: If you have your own custom database, implement AppDatabase
AppDatabase database = new DatabaseHelper(this,
DatabaseHelper.DEFAULT_NAME,
null,
DatabaseHelper.DEFAULT_VERSION);
StorageAccess.getInstance().init(pinCodeConfig, encryptionProvider, fileAccess, database);
}
}
The AndroidManifest
:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ch.usz.c3pro.demo.android">
<application
android:name=".C3PROApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
The build.gradle
:
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
applicationId "ch.usz.c3pro.demo"
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
// TODO: enabling multidex support.
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
dexOptions {
javaMaxHeapSize "3g"
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
// TODO: include C3PRO framework, but exclude some of the hapi library
compile ('ch.usz.c3pro:c3-pro-android-framework:0.1.2'){
exclude module: 'javax.servlet-api'
exclude module: 'hapi-fhir-base'
}
}
Once set up (preferably in your Application class, so it survives the Activities' lifesycles), the C3PRO will provide you with a HAPI FhirContext
and a DataQueue
if you have provided a FHIR Server URL.
You can access it anywhere in your app code, for example to get a JsonParser
:
C3PRO.getFhirContext().newJsonParser();
Or to upload a resource:
C3PRO.getDataQueue.create(resource);
Use the QuestionnaireFragment
to represent a Questionnaire and conduct a Survey based on it.
private void launchSurvey(Questionnaire questionnaire) {
/**
* Looking up if a fragment for the given questionnaire has been created earlier. if so,
* the survey is started, assuming that the TaskViewActivity has been created before!!
* The questionnaire IDs are used for identification, assuming they are unique.
* */
QuestionnaireFragment fragment = (QuestionnaireFragment) getSupportFragmentManager().findFragmentByTag(questionnaire.getId());
if (fragment != null) {
/**
* If the fragment has been added before, the TaskViewActivity can be started directly,
* assuming that it was prepared right after the fragment was created.
* */
fragment.startTaskViewActivity();
} else {
/**
* If the fragment does not exist, create it, add it to the fragment manager and
* let it prepare the TaskViewActivity
* */
final QuestionnaireFragment questionnaireFragment = new QuestionnaireFragment();
questionnaireFragment.newInstance(questionnaire, new QuestionnaireFragment.QuestionnaireFragmentListener() {
@Override
public void whenTaskReady(String requestID) {
/**
* Only when the task is ready, the survey is started
* */
questionnaireFragment.startTaskViewActivity();
}
@Override
public void whenCompleted(String requestID, QuestionnaireResponse questionnaireResponse) {
/**
* Where the response for a completed survey is received. Here it is printed
* to a TextView defined in the app layout.
* */
printQuestionnaireAnswers(questionnaireResponse);
}
@Override
public void whenCancelledOrFailed(C3PROErrorCode code) {
/**
* If the task can not be prepared, a backup plan is needed.
* Here the fragment is removed from the FragmentManager so it can be created
* again later
* */
if (code == C3PROErrorCode.RESULT_CANCELLED) {
/**
* user just cancelled activity. do nothing
* */
} else {
/**
* If the task can not be prepared, a backup plan is needed.
* Here the fragment is removed from the FragmentManager so it can be created
* again later.
* */
Log.e(LTAG, code.toString());
getSupportFragmentManager().beginTransaction().remove(questionnaireFragment).commit();
}
}
});
/**
* In order for the fragment to get the context and be found later on, it has to be added
* to the fragment manager.
* */
getSupportFragmentManager().beginTransaction().add(questionnaireFragment, questionnaire.getId()).commit();
/**
* prepare the TaskViewActivity. As defined above, it will start the survey once the
* TaskViewActivity is ready.
* */
questionnaireFragment.prepareTaskViewActivity();
}
}
The library uses HAPI FHIR 1.5 for dstu3. Questionnaires in dstu2 (with group and question elements) will not work with this demo setup. Target Android sdk is 23, minimum sdk 16 due to ResearchStack.
Implementation is ongoing, not everything is complete and nothing has been systematically tested.
- EnableWhen conditions have only been tested with boolean and singlechoice answertypes
- No proper error handling implemented as of yet.
The framework will consist of several modules that complement each other, similar to the C3-PRO ios framework.
Enables the conversion of a FHIR Questionnaire
resource to a ResearchSTack task
that can be presented to the user using a
ViewTaskActivity
and conversion back from a TaskResult
to a FHIR QuestionnaireResponse
resource.
This module provides a FHIR server implementation used to move FHIR resources, created on device, to a FHIR server, without the need for user interaction nor -confirmation.
This work will be Apache 2 licensed. A NOTICE.txt file will follow at some point, and don't forget to also add the licensing information of the submodules somewhere in your product: