Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into resource_consolid…
Browse files Browse the repository at this point in the history
…ation
  • Loading branch information
anchita-g committed Oct 9, 2023
2 parents a5d7f34 + 0818bd0 commit f81fb89
Show file tree
Hide file tree
Showing 54 changed files with 1,008 additions and 312 deletions.
20 changes: 20 additions & 0 deletions .github/dependabot.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
# Gotta Catch 'Em All! (i.e. don't wait and propose them only "trickled")
open-pull-requests-limit: 99

- package-ecosystem: gradle
directory: /
schedule:
interval: weekly
day: monday
time: "04:00"

- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
day: monday
time: "04:00"
51 changes: 51 additions & 0 deletions .github/workflows/codeql.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: "CodeQL"

on:
push:
branches: [ "master" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "master" ]
schedule:
- cron: '32 13 * * 2'

jobs:
analyze:
name: Analyze
runs-on: ubuntu-22.04-64core
timeout-minutes: 60
permissions:
actions: read
contents: read
security-events: write

strategy:
fail-fast: false
matrix:
language: [ 'java' ]

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Switch to Java 17 from Eclipse Temurin distro
uses: actions/setup-java@v3
with:
java-version: 17
distribution: temurin

- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}

# TODO: use Autobuild instead of ./gradlew after https://github.com/github/codeql-action/issues/1417 is fixed
# - name: Autobuild
# uses: github/codeql-action/autobuild@v2
- name: Build with Gradle
run: ./gradlew --scan --full-stacktrace -Dorg.gradle.dependency.verification=off compileDebugAndroidTestSources

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{matrix.language}}"
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Android FHIR SDK

[![master](https://github.com/google/android-fhir/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/google/android-fhir/actions/workflows/build.yml) [![master](https://storage.googleapis.com/android-fhir-build-badges/build.svg)](https://storage.googleapis.com/android-fhir-build-badges/build.html) [![codecov](https://codecov.io/gh/google/android-fhir/branch/master/graph/badge.svg?token=PDSC4WRDTQ)](https://codecov.io/gh/google/android-fhir/branch/master) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://chat.fhir.org/#narrow/stream/276344-android)
[![master](https://github.com/google/android-fhir/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/google/android-fhir/actions/workflows/build.yml) [![codecov](https://codecov.io/gh/google/android-fhir/branch/master/graph/badge.svg?token=PDSC4WRDTQ)](https://codecov.io/gh/google/android-fhir/branch/master) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://chat.fhir.org/#narrow/stream/276344-android)

The Android FHIR SDK is a set of Kotlin libraries for building offline-capable, mobile-first
healthcare applications using the [HL7® FHIR® standard](https://www.hl7.org/fhir/) on Android. It
Expand All @@ -15,7 +15,7 @@ The SDK contains the following libraries:
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Data Capture Library | [![Google Maven](https://badgen.net/maven/v/metadata-url/dl.google.com/dl/android/maven2/com/google/android/fhir/data-capture/maven-metadata.xml)](https://maven.google.com/web/index.html?#com.google.android.fhir:data-capture) | [code](https://github.com/google/android-fhir/tree/master/datacapture)| [wiki](https://github.com/google/android-fhir/wiki/Structured-Data-Capture-Library) | Android 7.0 (API level 24) | Collect, validate, and process healthcare data on Android |
| FHIR Engine Library | [![Google Maven](https://badgen.net/maven/v/metadata-url/dl.google.com/dl/android/maven2/com/google/android/fhir/engine/maven-metadata.xml)](https://maven.google.com/web/index.html?#com.google.android.fhir:engine) | [code](https://github.com/google/android-fhir/tree/master/engine) | [wiki](https://github.com/google/android-fhir/wiki/FHIR-Engine-Library) | Android 7.0 (API level 24) | Store and manage FHIR resources locally on Android and synchronize with FHIR server |
| Workflow Library | [![Google Maven](https://badgen.net/maven/v/metadata-url/dl.google.com/dl/android/maven2/com/google/android/fhir/workflow/maven-metadata.xml)](https://maven.google.com/web/index.html?#com.google.android.fhir:workflow) | [code](https://github.com/google/android-fhir/tree/master/workflow) | [wiki](https://github.com/google/android-fhir/wiki/Workflow-Library) | Android 8.0 (API level 26) | Provide decision support and analytics in clinical workflow on Android including implementation of specific FHIR operations ($measure_evaluate and $apply) |
| Workflow Library | [![Google Maven](https://badgen.net/maven/v/metadata-url/dl.google.com/dl/android/maven2/com/google/android/fhir/workflow/maven-metadata.xml)](https://maven.google.com/web/index.html?#com.google.android.fhir:workflow) | [code](https://github.com/google/android-fhir/tree/master/workflow) | [wiki](https://github.com/google/android-fhir/wiki/Workflow-Library) | Android 7.0 (API level 24) | Provide decision support and analytics in clinical workflow on Android including implementation of specific FHIR operations ($measure_evaluate and $apply) |

## Demo apps

Expand All @@ -38,7 +38,7 @@ To contribute to the project, please see [Contributing](https://github.com/googl

You can create a [GitHub issue](https://github.com/google/android-fhir/issues) for bugs and feature requests.

In case you find any security bug, please do NOT create a Github issue. Instead, email us at <[email protected]>.
In case you find any security bug, please do NOT create a GitHub issue. Instead, email us at <[email protected]>.

If you want to provide any feedback or discuss use cases you can:
* email us at <[email protected]>
Expand Down
4 changes: 4 additions & 0 deletions buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ object Dependencies {
"$androidFhirGroup:$androidFhirEngineModule:${Versions.androidFhirEngine}"
const val androidFhirKnowledge = "$androidFhirGroup:knowledge:${Versions.androidFhirKnowledge}"

const val apacheCommonsCompress =
"org.apache.commons:commons-compress:${Versions.apacheCommonsCompress}"

const val desugarJdkLibs = "com.android.tools:desugar_jdk_libs:${Versions.desugarJdkLibs}"
const val fhirUcum = "org.fhir:ucum:${Versions.fhirUcum}"
const val gson = "com.google.code.gson:gson:${Versions.gson}"
Expand Down Expand Up @@ -243,6 +246,7 @@ object Dependencies {
const val androidFhirCommon = "0.1.0-alpha04"
const val androidFhirEngine = "0.1.0-beta03"
const val androidFhirKnowledge = "0.1.0-alpha01"
const val apacheCommonsCompress = "1.21"
const val desugarJdkLibs = "2.0.3"
const val caffeine = "2.9.1"
const val fhirUcum = "1.0.3"
Expand Down
2 changes: 1 addition & 1 deletion catalog/src/main/assets/component_open_choice.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
}
}
],
"text": "Do you have any pre-existing health conditions?",
"text": "Do you have any preexisting health conditions?",
"item": [
{
"linkId": "1.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
}
],
"linkId": "1",
"text": "Do you have any pre-existing health conditions?",
"text": "Do you have any preexisting health conditions?",
"required": true,
"item": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
import com.google.android.fhir.datacapture.R
import com.google.android.fhir.datacapture.extensions.DisplayItemControlType
Expand Down Expand Up @@ -261,6 +262,7 @@ class QuestionnaireItemDialogMultiSelectViewHolderFactoryEspressoTest {
}

@Test
@SdkSuppress(minSdkVersion = 33) // TODO https://github.com/google/android-fhir/issues/1482 FIXME
fun selectOther_shouldScrollDownToShowAddAnotherAnswer() {
val questionnaireItem =
answerOptions(
Expand Down Expand Up @@ -327,6 +329,7 @@ class QuestionnaireItemDialogMultiSelectViewHolderFactoryEspressoTest {
}

@Test
@SdkSuppress(minSdkVersion = 33) // TODO https://github.com/google/android-fhir/issues/1482 FIXME
fun clickAddAnotherAnswer_shouldScrollDownToShowAddAnotherAnswer() {
val questionnaireItem =
answerOptions(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,7 @@ fun Questionnaire.QuestionnaireItemComponent.createQuestionnaireResponseItem():
}

/**
* Returns a list of answers from the initial values of the questionnaire item. `null` if no intial
* Returns a list of answers from the initial values of the questionnaire item. `null` if no initial
* value.
*/
private fun Questionnaire.QuestionnaireItemComponent.createQuestionnaireResponseItemAnswers():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,7 @@ class ResourceMapperTest {
}

@Test
fun `extract_updateIntegerObservationForDecimalDefination_shouldUpdateAsDecimal() `() =
fun `extract_updateIntegerObservationForDecimalDefinition_shouldUpdateAsDecimal() `() =
runBlocking {
@Language("JSON")
val questionnaireJson =
Expand Down
4 changes: 2 additions & 2 deletions docs/data-capture/scripts/navigation-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ revealParents = (part) => {
};

/*
This is a work-around for safari being IE of our times.
It doesn't fire a DOMContentLoaded, presumabely because eventListener is added after it wants to do it
This is a workaround for safari being IE of our times.
It doesn't fire a DOMContentLoaded, presumably because eventListener is added after it wants to do it
*/
if (document.readyState == 'loading') {
window.addEventListener('DOMContentLoaded', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ <h1 class="cover"><span>sync</span><wbr></wbr><span>Constraints</span></h1>
<div>
<div class="platform-hinted " data-platform-hinted="data-platform-hinted"><div class="content sourceset-depenent-content" data-active="" data-togglable=":engine:dokkaHtml/release"><div class="symbol monospace">val <a href="sync-constraints.html">syncConstraints</a>: <a href="https://developer.android.com/reference/kotlin/androidx/work/Constraints.html">Constraints</a><span class="top-right-position"><span class="copy-icon"></span><div class="copy-popup-wrapper popup-to-left"><span class="copy-popup-icon"></span><span>Content copied to clipboard</span></div></span></div></div></div>
</div>
<p class="paragraph">Constraints that specify the requirements needed before the synchronisation is triggered. E.g. network type (Wifi, 3G etc), the device should be charging etc.</p></div>
<p class="paragraph">Constraints that specify the requirements needed before the synchronisation is triggered. E.g. network type (WiFi, 3G etc), the device should be charging etc.</p></div>
<h2 class="">Sources</h2>
<div class="table" data-togglable="Sources"><a data-name="-1831107255%2FSource%2F-2001932064" anchor-label="https://github.com/google/android-fhir/tree/master/engine/src/main/java/com/google/android/fhir/sync/Config.kt#L51" id="-1831107255%2FSource%2F-2001932064" data-filterable-set=":engine:dokkaHtml/main"></a>
<div class="table-row" data-filterable-current=":engine:dokkaHtml/main" data-filterable-set=":engine:dokkaHtml/main">
Expand Down
4 changes: 2 additions & 2 deletions docs/engine/scripts/navigation-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ revealParents = (part) => {
};

/*
This is a work-around for safari being IE of our times.
It doesn't fire a DOMContentLoaded, presumabely because eventListener is added after it wants to do it
This is a workaround for safari being IE of our times.
It doesn't fire a DOMContentLoaded, presumably because eventListener is added after it wants to do it
*/
if (document.readyState == 'loading') {
window.addEventListener('DOMContentLoaded', () => {
Expand Down
15 changes: 15 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<body>

<h1>Android FHIR SDK Technical Documentation</h1>

<h2>API Docs</h2>
<ul>
<li><a href="engine/">engine</a></li>
<li><a href="data-capture/">data-capture</a></li>
<li><a href="workflow/">workflow</a></li>
</ul>

</body>
</html>
4 changes: 2 additions & 2 deletions docs/workflow/scripts/navigation-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ revealParents = (part) => {
};

/*
This is a work-around for safari being IE of our times.
It doesn't fire a DOMContentLoaded, presumabely because eventListener is added after it wants to do it
This is a workaround for safari being IE of our times.
It doesn't fire a DOMContentLoaded, presumably because eventListener is added after it wants to do it
*/
if (document.readyState == 'loading') {
window.addEventListener('DOMContentLoaded', () => {
Expand Down
13 changes: 5 additions & 8 deletions engine/benchmark/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,16 @@ configurations {
}

dependencies {
androidTestImplementation(Dependencies.Androidx.workRuntimeKtx)
androidTestImplementation(Dependencies.AndroidxTest.benchmarkJunit)
androidTestImplementation(Dependencies.AndroidxTest.extJunit)
androidTestImplementation(Dependencies.AndroidxTest.runner)
androidTestImplementation(Dependencies.Cql.engineJackson)
androidTestImplementation(Dependencies.Cql.evaluator)
androidTestImplementation(Dependencies.Cql.evaluatorBuilder)
androidTestImplementation(Dependencies.junit)
androidTestImplementation(Dependencies.Kotlin.kotlinCoroutinesAndroid)
androidTestImplementation(Dependencies.truth)
androidTestImplementation(Dependencies.Androidx.workRuntimeKtx)
androidTestImplementation(Dependencies.AndroidxTest.workTestingRuntimeKtx)
androidTestImplementation(Dependencies.mockWebServer)
androidTestImplementation(Dependencies.Kotlin.kotlinCoroutinesAndroid)
androidTestImplementation(Dependencies.Retrofit.coreRetrofit)
androidTestImplementation(Dependencies.junit)
androidTestImplementation(Dependencies.mockWebServer)
androidTestImplementation(Dependencies.truth)

androidTestImplementation(project(":engine"))
// for test json files only
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 8,
"identityHash": "81bc60d60855266f7fc233eb1c164a89",
"identityHash": "bf28146b530ec50ac067916072020d73",
"entities": [
{
"tableName": "ResourceEntity",
Expand Down Expand Up @@ -990,6 +990,15 @@
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_LocalChangeResourceReferenceEntity_resourceReferenceValue` ON `${TABLE_NAME}` (`resourceReferenceValue`)"
},
{
"name": "index_LocalChangeResourceReferenceEntity_localChangeId",
"unique": false,
"columnNames": [
"localChangeId"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_LocalChangeResourceReferenceEntity_localChangeId` ON `${TABLE_NAME}` (`localChangeId`)"
}
],
"foreignKeys": [
Expand All @@ -1010,7 +1019,7 @@
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '81bc60d60855266f7fc233eb1c164a89')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'bf28146b530ec50ac067916072020d73')"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import com.google.android.fhir.search.has
import com.google.android.fhir.search.include
import com.google.android.fhir.search.revInclude
import com.google.android.fhir.sync.upload.LocalChangesFetchMode
import com.google.android.fhir.sync.upload.UploadSyncResult
import com.google.android.fhir.testing.assertJsonArrayEqualsIgnoringOrder
import com.google.android.fhir.testing.assertResourceEquals
import com.google.android.fhir.testing.readFromFile
Expand All @@ -49,7 +50,7 @@ import com.google.common.truth.Truth.assertThat
import java.math.BigDecimal
import java.time.Instant
import java.util.Date
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.runBlocking
import org.hl7.fhir.r4.model.Address
import org.hl7.fhir.r4.model.CarePlan
Expand Down Expand Up @@ -529,19 +530,23 @@ class DatabaseImplTest {
database.insert(patient)
// Delete the patient created in setup as we only want to upload the patient in this test
database.deleteUpdates(listOf(TEST_PATIENT_1))
services.fhirEngine.syncUpload(LocalChangesFetchMode.AllChanges) {
it
.first { it.resourceId == "remote-patient-3" }
.let {
flowOf(
it.token to
Patient().apply {
id = it.resourceId
meta = remoteMeta
},
)
}
}
services.fhirEngine
.syncUpload(LocalChangesFetchMode.AllChanges) {
it
.first { it.resourceId == "remote-patient-3" }
.let {
UploadSyncResult.Success(
listOf(it),
listOf(
Patient().apply {
id = it.resourceId
meta = remoteMeta
},
),
)
}
}
.collect()
val selectedEntity = database.selectEntity(ResourceType.Patient, "remote-patient-3")
assertThat(selectedEntity.versionId).isEqualTo(remoteMeta.versionId)
assertThat(selectedEntity.lastUpdatedRemote).isEqualTo(remoteMeta.lastUpdated.toInstant())
Expand Down
18 changes: 13 additions & 5 deletions engine/src/main/java/com/google/android/fhir/FhirEngine.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import com.google.android.fhir.db.ResourceNotFoundException
import com.google.android.fhir.search.Search
import com.google.android.fhir.sync.ConflictResolver
import com.google.android.fhir.sync.upload.LocalChangesFetchMode
import com.google.android.fhir.sync.upload.SyncUploadProgress
import com.google.android.fhir.sync.upload.UploadSyncResult
import java.time.OffsetDateTime
import kotlinx.coroutines.flow.Flow
import org.hl7.fhir.r4.model.Resource
Expand Down Expand Up @@ -49,14 +51,20 @@ interface FhirEngine {
suspend fun <R : Resource> search(search: Search): List<SearchResult<R>>

/**
* Synchronizes the [upload] result in the database. [upload] operation may result in multiple
* calls to the server to upload the data. Result of each call will be emitted by [upload] and the
* api caller should [Flow.collect] it.
* Synchronizes the upload results in the database.
*
* The [upload] function may initiate multiple server calls. Each call's result can then be used
* to emit [UploadSyncResult]. The caller should collect these results using [Flow.collect].
*
* @param localChangesFetchMode Specifies the mode to fetch local changes.
* @param upload A suspend function that takes a list of [LocalChange] and returns an
* [UploadSyncResult].
* @return A [Flow] that emits the progress of the synchronization process.
*/
suspend fun syncUpload(
localChangesFetchMode: LocalChangesFetchMode,
upload: (suspend (List<LocalChange>) -> Flow<Pair<LocalChangeToken, Resource>>),
)
upload: (suspend (List<LocalChange>) -> UploadSyncResult),
): Flow<SyncUploadProgress>

/**
* Synchronizes the [download] result in the database. The database will be updated to reflect the
Expand Down
Loading

0 comments on commit f81fb89

Please sign in to comment.