diff --git a/build.gradle b/build.gradle index c3d0ee161..2900bd525 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ buildscript { versions.cacheword = '0.1.1' versions.glide = '4.15.0' versions.burgstallerOkhttpDigest = '3.1.1' - versions.javarosa = '2.6.0' + versions.javarosa = '4.4.0' versions.commonsIo = '2.6' versions.rxandroid = '2.1.1' versions.rxrelay = '2.1.1' @@ -94,6 +94,7 @@ buildscript { google() mavenCentral() maven { url 'https://jitpack.io' } // required for Nextcloud + } def isFdroid = project.hasProperty('fdroid') diff --git a/mobile/build.gradle b/mobile/build.gradle index d9c7101e2..d5376f91a 100644 --- a/mobile/build.gradle +++ b/mobile/build.gradle @@ -361,7 +361,7 @@ dependencies { // Add exclusions to prevent other libraries from pulling in xmlpull // JavaRosa - allow it to use xpp3 - implementation ("org.opendatakit:opendatakit-javarosa:$versions.javarosa") { + implementation ("org.getodk:javarosa:$versions.javarosa") { exclude group: "xmlpull", module: "xmlpull" // NO xpp3 exclusion - JavaRosa needs it } diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/database/DataSource.java b/mobile/src/main/java/org/horizontal/tella/mobile/data/database/DataSource.java index 99f3c4054..5ada61258 100644 --- a/mobile/src/main/java/org/horizontal/tella/mobile/data/database/DataSource.java +++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/database/DataSource.java @@ -1044,7 +1044,12 @@ private FormDef getCollectFormDef(CollectForm form) { if (cursor.moveToFirst()) { // todo: check if byte[] is empty and return null - return deserializeFormDef(cursor.getBlob(cursor.getColumnIndexOrThrow(D.C_FORM_DEF))); + byte[] data = cursor.getBlob(cursor.getColumnIndexOrThrow(D.C_FORM_DEF)); + if(data.length == 0) { + Timber.e("Empty"); + + } + return deserializeFormDef(data); } } catch (Exception e) { Timber.e(e, getClass().getName()); diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/data/entity/mapper/OpenRosaDataMapper.java b/mobile/src/main/java/org/horizontal/tella/mobile/data/entity/mapper/OpenRosaDataMapper.java index aaa77f205..b851776be 100644 --- a/mobile/src/main/java/org/horizontal/tella/mobile/data/entity/mapper/OpenRosaDataMapper.java +++ b/mobile/src/main/java/org/horizontal/tella/mobile/data/entity/mapper/OpenRosaDataMapper.java @@ -3,6 +3,7 @@ import android.net.Uri; import org.javarosa.core.model.FormDef; +import org.javarosa.xform.parse.XFormParser; import org.javarosa.xform.util.XFormUtils; import java.util.ArrayList; @@ -10,6 +11,8 @@ import okhttp3.ResponseBody; import retrofit2.Response; +import timber.log.Timber; + import org.horizontal.tella.mobile.data.entity.OpenRosaResponseEntity; import org.horizontal.tella.mobile.data.entity.XFormEntity; import org.horizontal.tella.mobile.data.http.HttpStatus; @@ -74,7 +77,12 @@ public FormDef transform(ResponseBody responseBody) { try { return XFormUtils.getFormFromInputStream(responseBody.byteStream()); - } finally { + } + catch(XFormParser.ParseException e) { + Timber.e(e, getClass().getSimpleName()); + return null; + } + finally { responseBody.close(); } } diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/javarosa/JavaRosa.java b/mobile/src/main/java/org/horizontal/tella/mobile/javarosa/JavaRosa.java index 8ea93e1c8..f7e443f95 100644 --- a/mobile/src/main/java/org/horizontal/tella/mobile/javarosa/JavaRosa.java +++ b/mobile/src/main/java/org/horizontal/tella/mobile/javarosa/JavaRosa.java @@ -26,31 +26,35 @@ public class JavaRosa { * Classes needed to serialize objects. Need to put anything from JR in here. */ private static final String[] SERIALIABLE_CLASSES = { - "org.javarosa.core.services.locale.ResourceFileDataSource", // JavaRosaCoreModule - "org.javarosa.core.services.locale.TableLocaleSource", // JavaRosaCoreModule + "org.javarosa.core.model.SubmissionProfile", "org.javarosa.core.model.FormDef", - "org.javarosa.core.model.SubmissionProfile", // CoreModelModule - "org.javarosa.core.model.QuestionDef", // CoreModelModule - "org.javarosa.core.model.GroupDef", // CoreModelModule - "org.javarosa.core.model.instance.FormInstance", // CoreModelModule - "org.javarosa.core.model.data.BooleanData", // CoreModelModule - "org.javarosa.core.model.data.DateData", // CoreModelModule - "org.javarosa.core.model.data.DateTimeData", // CoreModelModule - "org.javarosa.core.model.data.DecimalData", // CoreModelModule - "org.javarosa.core.model.data.GeoPointData", // CoreModelModule - "org.javarosa.core.model.data.GeoShapeData", // CoreModelModule - "org.javarosa.core.model.data.GeoTraceData", // CoreModelModule - "org.javarosa.core.model.data.IntegerData", // CoreModelModule - "org.javarosa.core.model.data.LongData", // CoreModelModule - "org.javarosa.core.model.data.MultiPointerAnswerData", // CoreModelModule - "org.javarosa.core.model.data.PointerAnswerData", // CoreModelModule - "org.javarosa.core.model.data.SelectMultiData", // CoreModelModule - "org.javarosa.core.model.data.SelectOneData", // CoreModelModule - "org.javarosa.core.model.data.StringData", // CoreModelModule - "org.javarosa.core.model.data.TimeData", // CoreModelModule - "org.javarosa.core.model.data.UncastData", // CoreModelModule - "org.javarosa.core.model.data.helper.BasicDataPointer", // CoreModelModule - "org.javarosa.core.model.actions.SetValueAction" // CoreModelModule + "org.javarosa.core.model.QuestionDef", + "org.javarosa.core.model.RangeQuestion", + "org.javarosa.core.model.GroupDef", + "org.javarosa.core.model.instance.TreeReference", + "org.javarosa.core.model.instance.FormInstance", + "org.javarosa.core.model.instance.ExternalDataInstance", + "org.javarosa.core.model.data.BooleanData", + "org.javarosa.core.model.data.DateData", + "org.javarosa.core.model.data.DateTimeData", + "org.javarosa.core.model.data.DecimalData", + "org.javarosa.core.model.data.GeoPointData", + "org.javarosa.core.model.data.GeoShapeData", + "org.javarosa.core.model.data.GeoTraceData", + "org.javarosa.core.model.data.IntegerData", + "org.javarosa.core.model.data.LongData", + "org.javarosa.core.model.data.MultiPointerAnswerData", + "org.javarosa.core.model.data.PointerAnswerData", + "org.javarosa.core.model.data.SelectMultiData", + "org.javarosa.core.model.data.MultipleItemsData", + "org.javarosa.core.model.data.SelectOneData", + "org.javarosa.core.model.data.StringData", + "org.javarosa.core.model.data.TimeData", + "org.javarosa.core.model.data.UncastData", + "org.javarosa.core.model.data.helper.BasicDataPointer", + "org.javarosa.core.model.actions.SetValueAction", + "org.javarosa.core.model.actions.setgeopoint.StubSetGeopointAction", + "org.javarosa.core.model.actions.recordaudio.RecordAudioAction" }; private static boolean isJavaRosaInitialized = false; diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/odk/FormController.java b/mobile/src/main/java/org/horizontal/tella/mobile/odk/FormController.java index 2eff718b8..45f39176a 100644 --- a/mobile/src/main/java/org/horizontal/tella/mobile/odk/FormController.java +++ b/mobile/src/main/java/org/horizontal/tella/mobile/odk/FormController.java @@ -297,14 +297,6 @@ public FormEntryCaption getCaptionPrompt() { } - /** - * This fires off the jr:preload actions and events to save values like the - * end time of a form. - */ - public boolean postProcessInstance() { - return formEntryController.getModel().getForm().postProcessInstance(); - } - /** * TODO: We need a good description of what this does, exactly, and why. diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/collect/widgets/RangeWidget.java b/mobile/src/main/java/org/horizontal/tella/mobile/views/collect/widgets/RangeWidget.java new file mode 100644 index 000000000..29b6b9482 --- /dev/null +++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/collect/widgets/RangeWidget.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2009 University of Washington + * + * 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 org.horizontal.tella.mobile.views.collect.widgets; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.view.LayoutInflater; +import android.widget.LinearLayout; +import android.widget.SeekBar; +import android.widget.TextView; + +import org.horizontal.tella.mobile.R; +import org.javarosa.core.model.Constants; +import org.javarosa.core.model.RangeQuestion; +import org.javarosa.core.model.data.IAnswerData; +import org.javarosa.core.model.data.IntegerData; +import org.javarosa.form.api.FormEntryPrompt; + + +/** + * Based on ODK Collect SelectOneWidget. + */ +@SuppressLint("ViewConstructor") +public class RangeWidget extends QuestionWidget + implements SeekBar.OnSeekBarChangeListener +{ + private SeekBar inputElement; + + private TextView rangeText; + + private int rangeStart; + private int range; + + public RangeWidget(Context context, FormEntryPrompt prompt) { + super(context, prompt); + + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.VERTICAL); + + LayoutInflater inflater = LayoutInflater.from(getContext()); + + inflater.inflate(R.layout.collect_widget_range, linearLayout, true); + + + RangeQuestion q = (RangeQuestion) prompt.getQuestion(); + + rangeStart = q.getRangeStart().intValue(); + final int rangeEnd = q.getRangeEnd().intValue(); + range = Math.abs(rangeEnd-rangeStart); + + final int rangeType = prompt.getDataType(); + if(rangeType == Constants.DATATYPE_INTEGER){ + inputElement = linearLayout.findViewById(R.id.seekBarDiscrete); + }//todo: handle non integer types? + + inputElement.setId(QuestionWidget.newUniqueId()); + inputElement.setMax(range); + + rangeText = linearLayout.findViewById(R.id.rangeText); + rangeText.setId(QuestionWidget.newUniqueId()); + + if (formEntryPrompt.getAnswerValue() == null) { + setAnswer(range/2); + } else { + rangeText.setText(formEntryPrompt.getAnswerText()); + Integer value = ((Integer)formEntryPrompt.getAnswerValue().getValue()); + inputElement.setProgress(Math.abs(q.getRangeStart().intValue())+value); + } + + inputElement.setOnSeekBarChangeListener(this); + + addAnswerView(linearLayout); + } + + protected void setAnswer(int value) { + inputElement.setProgress(value); + rangeText.setText(String.valueOf(value)); + } + + @Override + public void clearAnswer() { + setAnswer(range/2); + } + + @Override + public IAnswerData getAnswer() { + return new IntegerData(inputElement.getProgress() + rangeStart); + } + + @Override + public void setFocus(Context context) { + + } + + @Override + public void onProgressChanged(SeekBar seekBar, int i, boolean b) { + rangeText.setText(String.valueOf(seekBar.getProgress() - rangeStart)); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) {} + + @Override + public void onStopTrackingTouch(SeekBar seekBar) {} +} diff --git a/mobile/src/main/java/org/horizontal/tella/mobile/views/collect/widgets/WidgetFactory.java b/mobile/src/main/java/org/horizontal/tella/mobile/views/collect/widgets/WidgetFactory.java index 57700cc92..c126945e8 100644 --- a/mobile/src/main/java/org/horizontal/tella/mobile/views/collect/widgets/WidgetFactory.java +++ b/mobile/src/main/java/org/horizontal/tella/mobile/views/collect/widgets/WidgetFactory.java @@ -118,6 +118,10 @@ public static QuestionWidget createWidgetFromPrompt(FormEntryPrompt fep, Context questionWidget = new DocMediaWidget(context, fep); break; + case Constants.CONTROL_RANGE: + questionWidget = new RangeWidget(context, fep); + break; + default: questionWidget = new StringWidget(context, fep, readOnlyOverride); break; diff --git a/mobile/src/main/res/layout/collect_widget_range.xml b/mobile/src/main/res/layout/collect_widget_range.xml new file mode 100644 index 000000000..a32c37f8e --- /dev/null +++ b/mobile/src/main/res/layout/collect_widget_range.xml @@ -0,0 +1,31 @@ + + + + + + + + \ No newline at end of file