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