diff --git a/collect_app/src/main/java/org/odk/collect/android/application/initialization/JavaRosaInitializer.kt b/collect_app/src/main/java/org/odk/collect/android/application/initialization/JavaRosaInitializer.kt index 0fd0346311f..cba2b3edccd 100644 --- a/collect_app/src/main/java/org/odk/collect/android/application/initialization/JavaRosaInitializer.kt +++ b/collect_app/src/main/java/org/odk/collect/android/application/initialization/JavaRosaInitializer.kt @@ -9,6 +9,7 @@ import org.javarosa.xform.parse.XFormParserFactory import org.javarosa.xform.util.XFormUtils import org.odk.collect.android.dynamicpreload.DynamicPreloadXFormParserFactory import org.odk.collect.android.logic.actions.setgeopoint.CollectSetGeopointActionHandler +import org.odk.collect.android.preferences.SettingsExt.getExperimentalOptIn import org.odk.collect.android.projects.ProjectsDataService import org.odk.collect.entities.javarosa.intance.LocalEntitiesExternalInstanceParserFactory import org.odk.collect.entities.javarosa.parse.EntityXFormParserFactory @@ -16,6 +17,7 @@ import org.odk.collect.entities.storage.EntitiesRepository import org.odk.collect.metadata.PropertyManager import org.odk.collect.projects.ProjectDependencyFactory import org.odk.collect.settings.SettingsProvider +import org.odk.collect.settings.keys.ProjectKeys class JavaRosaInitializer( private val propertyManager: PropertyManager, @@ -45,7 +47,7 @@ class JavaRosaInitializer( val entityXFormParserFactory = EntityXFormParserFactory( XFormParserFactory() - ) + ) { settingsProvider.getUnprotectedSettings().getExperimentalOptIn(ProjectKeys.KEY_ENTITIES_SPEC_V2025_1) } val dynamicPreloadXFormParserFactory = DynamicPreloadXFormParserFactory(entityXFormParserFactory) diff --git a/collect_app/src/main/java/org/odk/collect/android/preferences/Defaults.kt b/collect_app/src/main/java/org/odk/collect/android/preferences/Defaults.kt index 4995f04e50c..eed87d48bab 100644 --- a/collect_app/src/main/java/org/odk/collect/android/preferences/Defaults.kt +++ b/collect_app/src/main/java/org/odk/collect/android/preferences/Defaults.kt @@ -54,6 +54,7 @@ object Defaults { // experimental_preferences.xml hashMap[ProjectKeys.KEY_DEBUG_FILTERS] = BuildConfig.BUILD_TYPE == "selfSignedRelease" hashMap[ProjectKeys.KEY_ZXING_SCANNING] = false + hashMap[ProjectKeys.KEY_ENTITIES_SPEC_V2025_1] = false return hashMap } diff --git a/collect_app/src/main/res/xml/experimental_preferences.xml b/collect_app/src/main/res/xml/experimental_preferences.xml index 5acf249a54f..9d77e85b0b6 100644 --- a/collect_app/src/main/res/xml/experimental_preferences.xml +++ b/collect_app/src/main/res/xml/experimental_preferences.xml @@ -14,6 +14,11 @@ app:allowDividerBelow="false" app:iconSpaceReserved="false"> + + Boolean +) : BindAttributeProcessor, FormDefProcessor, ModelAttributeProcessor { private val saveTos = mutableListOf>() private var version: String? = null @@ -28,7 +29,7 @@ class EntityFormParseProcessor : BindAttributeProcessor, FormDefProcessor, Model override fun processModelAttribute(name: String, value: String) { version = value - if (BuildConfig.DEBUG && value.startsWith(V2025_1)) { + if (value.startsWith(V2025_1) && v2025enabled()) { return } diff --git a/entities/src/main/java/org/odk/collect/entities/javarosa/parse/EntityXFormParserFactory.java b/entities/src/main/java/org/odk/collect/entities/javarosa/parse/EntityXFormParserFactory.java deleted file mode 100644 index 6e735509e00..00000000000 --- a/entities/src/main/java/org/odk/collect/entities/javarosa/parse/EntityXFormParserFactory.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.odk.collect.entities.javarosa.parse; - -import org.javarosa.xform.parse.IXFormParserFactory; -import org.javarosa.xform.parse.XFormParser; -import org.jetbrains.annotations.NotNull; - -public class EntityXFormParserFactory extends IXFormParserFactory.Wrapper { - - public EntityXFormParserFactory(IXFormParserFactory base) { - super(base); - } - - @Override - public XFormParser apply(@NotNull XFormParser parser) { - EntityFormParseProcessor processor = new EntityFormParseProcessor(); - parser.addProcessor(processor); - - return parser; - } -} diff --git a/entities/src/main/java/org/odk/collect/entities/javarosa/parse/EntityXFormParserFactory.kt b/entities/src/main/java/org/odk/collect/entities/javarosa/parse/EntityXFormParserFactory.kt new file mode 100644 index 00000000000..3e870edd0e6 --- /dev/null +++ b/entities/src/main/java/org/odk/collect/entities/javarosa/parse/EntityXFormParserFactory.kt @@ -0,0 +1,16 @@ +package org.odk.collect.entities.javarosa.parse + +import org.javarosa.xform.parse.IXFormParserFactory +import org.javarosa.xform.parse.XFormParser + +class EntityXFormParserFactory( + base: IXFormParserFactory, + private val v2025enabled: () -> Boolean +) : IXFormParserFactory.Wrapper(base) { + override fun apply(parser: XFormParser): XFormParser { + val processor = EntityFormParseProcessor(v2025enabled) + parser.addProcessor(processor) + + return parser + } +} diff --git a/entities/src/test/java/org/odk/collect/entities/javarosa/EntitiesTest.java b/entities/src/test/java/org/odk/collect/entities/javarosa/EntitiesTest.java index 8d85772d964..00b72181407 100644 --- a/entities/src/test/java/org/odk/collect/entities/javarosa/EntitiesTest.java +++ b/entities/src/test/java/org/odk/collect/entities/javarosa/EntitiesTest.java @@ -39,7 +39,7 @@ public class EntitiesTest { - private final EntityXFormParserFactory entityXFormParserFactory = new EntityXFormParserFactory(new XFormParserFactory()); + private final EntityXFormParserFactory entityXFormParserFactory = new EntityXFormParserFactory(new XFormParserFactory(), () -> false); @Before public void setup() { diff --git a/entities/src/test/java/org/odk/collect/entities/javarosa/EntityFormFinalizationProcessorTest.java b/entities/src/test/java/org/odk/collect/entities/javarosa/EntityFormFinalizationProcessorTest.java index 4dbebcf3cae..55a3a925f45 100644 --- a/entities/src/test/java/org/odk/collect/entities/javarosa/EntityFormFinalizationProcessorTest.java +++ b/entities/src/test/java/org/odk/collect/entities/javarosa/EntityFormFinalizationProcessorTest.java @@ -38,7 +38,7 @@ public class EntityFormFinalizationProcessorTest { - private final EntityXFormParserFactory entityXFormParserFactory = new EntityXFormParserFactory(new XFormParserFactory()); + private final EntityXFormParserFactory entityXFormParserFactory = new EntityXFormParserFactory(new XFormParserFactory(), () -> false); @Before public void setup() { diff --git a/entities/src/test/java/org/odk/collect/entities/javarosa/EntityFormParseProcessorTest.java b/entities/src/test/java/org/odk/collect/entities/javarosa/EntityFormParseProcessorTest.java index 6f1f676be3b..c687dda4195 100644 --- a/entities/src/test/java/org/odk/collect/entities/javarosa/EntityFormParseProcessorTest.java +++ b/entities/src/test/java/org/odk/collect/entities/javarosa/EntityFormParseProcessorTest.java @@ -53,7 +53,7 @@ public void whenVersionIsMissing_parsesWithoutError() throws XFormParser.ParseEx ) ); - EntityFormParseProcessor processor = new EntityFormParseProcessor(); + EntityFormParseProcessor processor = new EntityFormParseProcessor(() -> false); XFormParser parser = new XFormParser(new InputStreamReader(new ByteArrayInputStream(form.asXml().getBytes()))); parser.addProcessor(processor); parser.parse(null); @@ -84,7 +84,7 @@ public void whenVersionIsMissing_andThereIsAnEntityElement_throwsException() { ) ); - EntityFormParseProcessor processor = new EntityFormParseProcessor(); + EntityFormParseProcessor processor = new EntityFormParseProcessor(() -> false); XFormParser parser = new XFormParser(new InputStreamReader(new ByteArrayInputStream(form.asXml().getBytes()))); parser.addProcessor(processor); @@ -125,7 +125,7 @@ public void whenVersionIsNotRecognized_throwsException() throws XFormParser.Pars ) ); - EntityFormParseProcessor processor = new EntityFormParseProcessor(); + EntityFormParseProcessor processor = new EntityFormParseProcessor(() -> false); XFormParser parser = new XFormParser(new InputStreamReader(new ByteArrayInputStream(form.asXml().getBytes()))); parser.addProcessor(processor); parser.parse(null); @@ -158,7 +158,7 @@ public void whenVersionIsNewPatch_parsesCorrectly() throws XFormParser.ParseExce ) ); - EntityFormParseProcessor processor = new EntityFormParseProcessor(); + EntityFormParseProcessor processor = new EntityFormParseProcessor(() -> false); XFormParser parser = new XFormParser(new InputStreamReader(new ByteArrayInputStream(form.asXml().getBytes()))); parser.addProcessor(processor); @@ -193,7 +193,7 @@ public void whenVersionIsNewVersionWithUpdates_parsesCorrectly() throws XFormPar ) ); - EntityFormParseProcessor processor = new EntityFormParseProcessor(); + EntityFormParseProcessor processor = new EntityFormParseProcessor(() -> false); XFormParser parser = new XFormParser(new InputStreamReader(new ByteArrayInputStream(form.asXml().getBytes()))); parser.addProcessor(processor); @@ -227,11 +227,79 @@ public void saveTosWithIncorrectNamespaceAreIgnored() throws XFormParser.ParseEx ) ); - EntityFormParseProcessor processor = new EntityFormParseProcessor(); + EntityFormParseProcessor processor = new EntityFormParseProcessor(() -> false); XFormParser parser = new XFormParser(new InputStreamReader(new ByteArrayInputStream(form.asXml().getBytes()))); parser.addProcessor(processor); FormDef formDef = parser.parse(null); assertThat(formDef.getExtras().get(EntityFormExtra.class).getSaveTos(), is(empty())); } + + @Test + public void whenVersionIs2025_1_andFeatureIsEnabled_parsesCorrectly() throws XFormParser.ParseException { + String updateVersion = "2025.1.0"; + + XFormsElement form = XFormsElement.html( + asList( + new Pair<>("entities", "http://www.opendatakit.org/xforms/entities") + ), + head( + title("Create entity form"), + model(asList(new Pair<>("entities:entities-version", updateVersion)), + mainInstance( + t("data id=\"update-entity-form\"", + t("name"), + t("meta", + t("entity dataset=\"people\" update=\"1\" id=\"17\"") + ) + ) + ), + bind("/data/name").type("string").withAttribute("entities", "saveto", "name") + ) + ), + body( + input("/data/name") + ) + ); + + EntityFormParseProcessor processor = new EntityFormParseProcessor(() -> true); + XFormParser parser = new XFormParser(new InputStreamReader(new ByteArrayInputStream(form.asXml().getBytes()))); + parser.addProcessor(processor); + + FormDef formDef = parser.parse(null); + assertThat(formDef, notNullValue()); + } + + @Test(expected = UnrecognizedEntityVersionException.class) + public void whenVersionIs2025_1_andFeatureIsDisabled_throwsException() throws XFormParser.ParseException { + String updateVersion = "2025.1.0"; + + XFormsElement form = XFormsElement.html( + asList( + new Pair<>("entities", "http://www.opendatakit.org/xforms/entities") + ), + head( + title("Create entity form"), + model(asList(new Pair<>("entities:entities-version", updateVersion)), + mainInstance( + t("data id=\"update-entity-form\"", + t("name"), + t("meta", + t("entity dataset=\"people\" update=\"1\" id=\"17\"") + ) + ) + ), + bind("/data/name").type("string").withAttribute("entities", "saveto", "name") + ) + ), + body( + input("/data/name") + ) + ); + + EntityFormParseProcessor processor = new EntityFormParseProcessor(() -> false); + XFormParser parser = new XFormParser(new InputStreamReader(new ByteArrayInputStream(form.asXml().getBytes()))); + parser.addProcessor(processor); + parser.parse(null); + } } diff --git a/settings/src/main/java/org/odk/collect/settings/keys/ProjectKeys.kt b/settings/src/main/java/org/odk/collect/settings/keys/ProjectKeys.kt index efc04321a76..3755d0b3d67 100644 --- a/settings/src/main/java/org/odk/collect/settings/keys/ProjectKeys.kt +++ b/settings/src/main/java/org/odk/collect/settings/keys/ProjectKeys.kt @@ -54,6 +54,7 @@ object ProjectKeys { // experimental_preferences.xml const val KEY_DEBUG_FILTERS = "experimental_debug_filters" const val KEY_ZXING_SCANNING = "zxing_scanning" + const val KEY_ENTITIES_SPEC_V2025_1 = "entities_spec_v2025_1" // values const val PROTOCOL_SERVER = "odk_default" diff --git a/strings/src/main/res/values/strings.xml b/strings/src/main/res/values/strings.xml index a1a4ec7753b..9896cdf24ac 100644 --- a/strings/src/main/res/values/strings.xml +++ b/strings/src/main/res/values/strings.xml @@ -1229,7 +1229,8 @@ Entity lists - + + Enable entities spec v2025.1 View entity lists