Skip to content

Commit

Permalink
Support location widget to get current location (google#2341)
Browse files Browse the repository at this point in the history
* Support location widget to get current location

Added a custom location-widget as contrib/locationwidget library

* Allow License https://developer.android.com/studio/terms.html

* Remove unnecesary unit view for location widget

* Update tests for contrib locationwidget

---------

Co-authored-by: Jing Tang <jingtang@google.com>
  • Loading branch information
LZRS and jingtang10 authored Feb 7, 2024
1 parent 35b7272 commit 4169a8d
Show file tree
Hide file tree
Showing 28 changed files with 886 additions and 21 deletions.
7 changes: 7 additions & 0 deletions buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ object Dependencies {
const val kotlinTestJunit = "org.jetbrains.kotlin:kotlin-test-junit:${Versions.Kotlin.stdlib}"
const val kotlinCoroutinesTest =
"org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.Kotlin.kotlinCoroutinesCore}"
const val kotlinCoroutinesPlay =
"org.jetbrains.kotlinx:kotlinx-coroutines-play-services:${Versions.Kotlin.kotlinCoroutinesCore}"
const val stdlib = "org.jetbrains.kotlin:kotlin-stdlib:${Versions.Kotlin.stdlib}"
}

Expand Down Expand Up @@ -155,6 +157,9 @@ object Dependencies {
"com.google.mlkit:object-detection-custom:${Versions.Mlkit.objectDetectionCustom}"
}

const val playServicesLocation =
"com.google.android.gms:play-services-location:${Versions.playServicesLocation}"

const val androidFhirGroup = "com.google.android.fhir"
const val androidFhirEngineModule = "engine"
const val androidFhirKnowledgeModule = "knowledge"
Expand Down Expand Up @@ -307,6 +312,8 @@ object Dependencies {
const val objectDetection = "16.2.3"
const val objectDetectionCustom = "16.3.1"
}

const val playServicesLocation = "21.0.1"
}

fun Configuration.removeIncompatibleDependencies() {
Expand Down
6 changes: 5 additions & 1 deletion buildSrc/src/main/kotlin/LicenseeConfig.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Google LLC
* Copyright 2023-2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -116,13 +116,15 @@ fun Project.configureLicensee() {
// https://developers.google.com/android/reference/com/google/android/gms/common/package-summary
allowDependency("com.google.android.gms", "play-services-base", "17.4.0") { because("") }
allowDependency("com.google.android.gms", "play-services-base", "18.0.1") { because("") }
allowDependency("com.google.android.gms", "play-services-base", "18.1.0") { because("") }

allowDependency("com.google.android.odml", "image", "1.0.0-beta1") { because("") }

// More utility classes
// https://developers.google.com/android/reference/com/google/android/gms/common/package-summary
allowDependency("com.google.android.gms", "play-services-basement", "17.4.0") { because("") }
allowDependency("com.google.android.gms", "play-services-basement", "18.0.0") { because("") }
allowDependency("com.google.android.gms", "play-services-basement", "18.1.0") { because("") }

// https://developers.google.com/android/reference/com/google/android/gms/common/package-summary
allowDependency("com.google.android.gms", "play-services-clearcut", "17.0.0") { because("") }
Expand All @@ -138,6 +140,7 @@ fun Project.configureLicensee() {
// Tasks API Android https://developers.google.com/android/guides/tasks
allowDependency("com.google.android.gms", "play-services-tasks", "17.2.0") { because("") }
allowDependency("com.google.android.gms", "play-services-tasks", "18.0.1") { because("") }
allowDependency("com.google.android.gms", "play-services-tasks", "18.0.2") { because("") }

// Barcode Scanning https://developers.google.com/ml-kit/vision/barcode-scanning
allowDependency("com.google.mlkit", "barcode-scanning", "16.1.1") { because("") }
Expand Down Expand Up @@ -201,4 +204,5 @@ private val nonStandardLicenseUrls =
"http://opensource.org/licenses/BSD-3-Clause",
"http://www.opensource.org/licenses/bsd-license.php",
"https://asm.ow2.io/license.html",
"https://developer.android.com/studio/terms.html",
)
7 changes: 7 additions & 0 deletions buildSrc/src/main/kotlin/Releases.kt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ object Releases {
override val version = "0.1.0-beta3"
override val name = "Android FHIR Structured Data Capture - Barcode Extensions (contrib)"
}

object LocationWidget : LibraryArtifact {
override val artifactId = "contrib-locationwidget"
override val version = "0.1.0-alpha01"
override val name =
"Android FHIR Structured Data Capture - Location Widget Extensions (contrib)"
}
}

object Knowledge : LibraryArtifact {
Expand Down
1 change: 1 addition & 0 deletions catalog/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ dependencies {
implementation(project(path = ":datacapture"))
implementation(project(path = ":engine"))
implementation(project(path = ":contrib:barcode"))
implementation(project(path = ":contrib:locationwidget"))

testImplementation(Dependencies.junit)
}
52 changes: 52 additions & 0 deletions catalog/src/main/assets/component_location_widget.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"resourceType": "Questionnaire",
"language": "en",
"status": "active",
"date": "2020-11-18T07:24:47.111Z",
"item": [
{
"linkId": "location-widget",
"type": "group",
"text": "Location Widget",
"extension": [
{
"url": "https://github.com/google/android-fhir/StructureDefinition/questionnaire-itemControl",
"valueCodeableConcept": {
"coding": [
{
"system": "https://github.com/google/android-fhir/questionnaire-item-control",
"code": "location-widget"
}
]
}
}
],
"item": [
{
"linkId": "latitude",
"type": "decimal",
"required": true,
"text": "Latitude",
"extension": [
{
"url": "gps-coordinate",
"valueString": "latitude"
}
]
},
{
"linkId": "longitude",
"type": "decimal",
"required": true,
"text": "Longitude",
"extension": [
{
"url": "gps-coordinate",
"valueString": "longitude"
}
]
}
]
}
]
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2023 Google LLC
* Copyright 2022-2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -40,7 +40,11 @@ class CatalogApplication : Application(), DataCaptureConfig.Provider {
FhirEngineProvider.init(FhirEngineConfiguration())

dataCaptureConfig =
DataCaptureConfig(xFhirQueryResolver = { fhirEngine.search(it).map { it.resource } })
DataCaptureConfig(
xFhirQueryResolver = { fhirEngine.search(it).map { it.resource } },
questionnaireItemViewHolderFactoryMatchersProviderFactory =
ContribQuestionnaireItemViewHolderFactoryMatchersProviderFactory,
)

CoroutineScope(Dispatchers.IO).launch {
assets
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ class ComponentListViewModel(application: Application, private val state: SavedS
R.string.component_name_initial_value,
"component_initial_value.json",
),
LOCATION_WIDGET(
R.drawable.ic_location_on,
R.string.component_name_location_widget,
"component_location_widget.json",
),
}

val viewItemList =
Expand All @@ -171,6 +176,7 @@ class ComponentListViewModel(application: Application, private val state: SavedS
ViewItem.ComponentItem(Component.ITEM_MEDIA),
ViewItem.ComponentItem(Component.ITEM_ANSWER_MEDIA),
ViewItem.ComponentItem(Component.INITIAL_VALUE),
ViewItem.ComponentItem(Component.LOCATION_WIDGET),
)

fun isComponent(context: Context, title: String) =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.android.fhir.catalog

import com.google.android.fhir.datacapture.QuestionnaireFragment
import com.google.android.fhir.datacapture.QuestionnaireItemViewHolderFactoryMatchersProviderFactory
import com.google.android.fhir.datacapture.contrib.views.locationwidget.LocationGpsCoordinateViewHolderFactory
import com.google.android.fhir.datacapture.contrib.views.locationwidget.LocationWidgetViewHolderFactory

object ContribQuestionnaireItemViewHolderFactoryMatchersProviderFactory :
QuestionnaireItemViewHolderFactoryMatchersProviderFactory {

const val LOCATION_WIDGET_PROVIDER = "location-widget-provider"

override fun get(
provider: String,
): QuestionnaireFragment.QuestionnaireItemViewHolderFactoryMatchersProvider =
when (provider) {
LOCATION_WIDGET_PROVIDER ->
object : QuestionnaireFragment.QuestionnaireItemViewHolderFactoryMatchersProvider() {
override fun get():
List<QuestionnaireFragment.QuestionnaireItemViewHolderFactoryMatcher> {
return listOf(
QuestionnaireFragment.QuestionnaireItemViewHolderFactoryMatcher(
factory = LocationGpsCoordinateViewHolderFactory,
matches = LocationGpsCoordinateViewHolderFactory::matcher,
),
QuestionnaireFragment.QuestionnaireItemViewHolderFactoryMatcher(
factory = LocationWidgetViewHolderFactory,
matches = LocationWidgetViewHolderFactory::matcher,
),
)
}
}
else -> throw NotImplementedError()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,13 @@ class DemoQuestionnaireFragment : Fragment() {
setReorderingAllowed(true)
val questionnaireFragment =
QuestionnaireFragment.builder()
.apply { setQuestionnaire(args.questionnaireJsonStringKey!!) }
.apply {
setCustomQuestionnaireItemViewHolderFactoryMatchersProvider(
ContribQuestionnaireItemViewHolderFactoryMatchersProviderFactory
.LOCATION_WIDGET_PROVIDER,
)
setQuestionnaire(args.questionnaireJsonStringKey!!)
}
.build()
add(R.id.container, questionnaireFragment, QUESTIONNAIRE_FRAGMENT_TAG)
}
Expand Down
13 changes: 13 additions & 0 deletions catalog/src/main/res/drawable/ic_location_on.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="128dp"
android:height="128dp"
android:tint="#1A73E8"
android:viewportWidth="24"
android:viewportHeight="24"
>
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM12,11.5c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5z"
/>
</vector>
1 change: 1 addition & 0 deletions catalog/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
<string name="component_name_item_answer_media">Item Answer Media</string>
<string name="component_name_repeated_group">Repeated Group</string>
<string name="component_name_attachment">Attachment</string>
<string name="component_name_location_widget">Location Widget</string>
<string name="layout_name_default_text">Default</string>
<string name="layout_name_paginated">Paginated</string>
<string name="layout_name_review">Review</string>
Expand Down
1 change: 1 addition & 0 deletions contrib/locationwidget/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
75 changes: 75 additions & 0 deletions contrib/locationwidget/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import Dependencies.removeIncompatibleDependencies

plugins {
id(Plugins.BuildPlugins.androidLib)
id(Plugins.BuildPlugins.kotlinAndroid)
id(Plugins.BuildPlugins.mavenPublish)
jacoco
}

publishArtifact(Releases.Contrib.LocationWidget)

createJacocoTestReportTask()

android {
namespace = "com.google.android.fhir.datacapture.contrib.views.locationwidget"
compileSdk = Sdk.compileSdk
defaultConfig {
minSdk = Sdk.minSdk
testInstrumentationRunner = Dependencies.androidJunitRunner
// Need to specify this to prevent junit runner from going deep into our dependencies
testInstrumentationRunnerArguments["package"] = "com.google.android.fhir.datacapture"
}

buildFeatures { viewBinding = true }

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"))
}
}

packaging {
resources.excludes.addAll(
listOf(
"META-INF/INDEX.LIST",
"META-INF/ASL2.0",
"META-INF/ASL-2.0.txt",
"META-INF/LGPL-3.0.txt",
),
)
}

configureJacocoTestOptions()

testOptions { animationsDisabled = true }
kotlin { jvmToolchain(11) }
}

configurations { all { removeIncompatibleDependencies() } }

dependencies {
implementation(project(":datacapture"))
implementation(Dependencies.Androidx.coreKtx)
implementation(Dependencies.Androidx.fragmentKtx)
implementation(Dependencies.playServicesLocation)
implementation(Dependencies.Kotlin.kotlinCoroutinesPlay)
implementation(Dependencies.material)
implementation(Dependencies.timber)
implementation(Dependencies.Androidx.appCompat)

testImplementation(Dependencies.AndroidxTest.fragmentTesting)
testImplementation(Dependencies.Kotlin.kotlinTestJunit)
testImplementation(Dependencies.junit)
testImplementation(Dependencies.robolectric)
testImplementation(Dependencies.truth)

androidTestImplementation(Dependencies.AndroidxTest.core)
androidTestImplementation(Dependencies.AndroidxTest.extJunit)
androidTestImplementation(Dependencies.AndroidxTest.extJunitKtx)
androidTestImplementation(Dependencies.AndroidxTest.fragmentTesting)
androidTestImplementation(Dependencies.AndroidxTest.rules)
androidTestImplementation(Dependencies.AndroidxTest.runner)
androidTestImplementation(Dependencies.truth)
}
Loading

0 comments on commit 4169a8d

Please sign in to comment.