use of org.odk.collect.android.logic.FormController in project collect by opendatakit.
the class FormEntryActivity method onSaveInstanceState.
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(KEY_FORMPATH, formPath);
FormController formController = getFormController();
if (formController != null) {
if (formController.getInstanceFile() != null) {
outState.putString(KEY_INSTANCEPATH, getAbsoluteInstancePath());
}
outState.putString(KEY_XPATH, formController.getXPath(formController.getFormIndex()));
FormIndex waiting = formController.getIndexWaitingForData();
if (waiting != null) {
outState.putString(KEY_XPATH_WAITING_FOR_DATA, formController.getXPath(waiting));
}
// save the instance to a temp path...
nonblockingCreateSavePointData();
}
outState.putBoolean(NEWFORM, false);
outState.putString(KEY_ERROR, errorMessage);
outState.putString(KEY_SAVE_NAME, saveName);
outState.putBoolean(KEY_AUTO_SAVED, autoSaved);
if (currentView instanceof ODKView) {
outState.putAll(((ODKView) currentView).getState());
// This value is originally set in onCreate() method but if you only minimize the app or
// block/unblock the screen, onCreate() method might not be called (if the activity is just paused
// not stopped https://developer.android.com/guide/components/activities/activity-lifecycle.html)
state = outState;
}
}
use of org.odk.collect.android.logic.FormController in project collect by opendatakit.
the class FormEntryActivity method onActivityResult.
@Override
protected void onActivityResult(int requestCode, int resultCode, final Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
FormController formController = getFormController();
if (formController == null) {
// try to save this callback data to the FormLoaderTask
if (formLoaderTask != null && formLoaderTask.getStatus() != AsyncTask.Status.FINISHED) {
formLoaderTask.setActivityResult(requestCode, resultCode, intent);
} else {
Timber.e("Got an activityResult without any pending form loader");
}
return;
}
if (resultCode == RESULT_CANCELED) {
// request was canceled...
if (requestCode != RequestCodes.HIERARCHY_ACTIVITY && getCurrentViewIfODKView() != null) {
getCurrentViewIfODKView().cancelWaitingForBinaryData();
}
return;
}
// intent is needed for all requestCodes except of DRAW_IMAGE, ANNOTATE_IMAGE, SIGNATURE_CAPTURE, IMAGE_CAPTURE and HIERARCHY_ACTIVITY
if (intent == null && requestCode != RequestCodes.DRAW_IMAGE && requestCode != RequestCodes.ANNOTATE_IMAGE && requestCode != RequestCodes.SIGNATURE_CAPTURE && requestCode != RequestCodes.IMAGE_CAPTURE && requestCode != RequestCodes.HIERARCHY_ACTIVITY) {
Timber.w("The intent has a null value for requestCode: " + requestCode);
ToastUtils.showLongToast(getString(R.string.null_intent_value));
return;
}
// For handling results returned by the Zxing Barcode scanning library
IntentResult barcodeScannerResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
if (barcodeScannerResult != null) {
if (barcodeScannerResult.getContents() == null) {
// request was canceled...
Timber.i("QR code scanning cancelled");
} else {
String sb = intent.getStringExtra("SCAN_RESULT");
if (getCurrentViewIfODKView() != null) {
getCurrentViewIfODKView().setBinaryData(sb);
}
saveAnswersForCurrentScreen(DO_NOT_EVALUATE_CONSTRAINTS);
refreshCurrentView();
return;
}
}
switch(requestCode) {
case RequestCodes.OSM_CAPTURE:
String osmFileName = intent.getStringExtra("OSM_FILE_NAME");
if (getCurrentViewIfODKView() != null) {
getCurrentViewIfODKView().setBinaryData(osmFileName);
}
saveAnswersForCurrentScreen(DO_NOT_EVALUATE_CONSTRAINTS);
break;
case RequestCodes.EX_STRING_CAPTURE:
case RequestCodes.EX_INT_CAPTURE:
case RequestCodes.EX_DECIMAL_CAPTURE:
String key = "value";
boolean exists = intent.getExtras().containsKey(key);
if (exists) {
Object externalValue = intent.getExtras().get(key);
if (getCurrentViewIfODKView() != null) {
getCurrentViewIfODKView().setBinaryData(externalValue);
}
saveAnswersForCurrentScreen(DO_NOT_EVALUATE_CONSTRAINTS);
}
break;
case RequestCodes.EX_GROUP_CAPTURE:
try {
Bundle extras = intent.getExtras();
if (getCurrentViewIfODKView() != null) {
getCurrentViewIfODKView().setDataForFields(extras);
}
} catch (JavaRosaException e) {
Timber.e(e);
createErrorDialog(e.getCause().getMessage(), DO_NOT_EXIT);
}
break;
case RequestCodes.DRAW_IMAGE:
case RequestCodes.ANNOTATE_IMAGE:
case RequestCodes.SIGNATURE_CAPTURE:
case RequestCodes.IMAGE_CAPTURE:
/*
* We saved the image to the tempfile_path, but we really want it to
* be in: /sdcard/odk/instances/[current instnace]/something.jpg so
* we move it there before inserting it into the content provider.
* Once the android image capture bug gets fixed, (read, we move on
* from Android 1.6) we want to handle images the audio and video
*/
// The intent is empty, but we know we saved the image to the temp
// file
ImageConverter.execute(Collect.TMPFILE_PATH, getWidgetWaitingForBinaryData(), this);
File fi = new File(Collect.TMPFILE_PATH);
String instanceFolder = formController.getInstanceFile().getParent();
String s = instanceFolder + File.separator + System.currentTimeMillis() + ".jpg";
File nf = new File(s);
if (!fi.renameTo(nf)) {
Timber.e("Failed to rename %s", fi.getAbsolutePath());
} else {
Timber.i("Renamed %s to %s", fi.getAbsolutePath(), nf.getAbsolutePath());
}
if (getCurrentViewIfODKView() != null) {
getCurrentViewIfODKView().setBinaryData(nf);
}
saveAnswersForCurrentScreen(DO_NOT_EVALUATE_CONSTRAINTS);
break;
case RequestCodes.ALIGNED_IMAGE:
/*
* We saved the image to the tempfile_path; the app returns the full
* path to the saved file in the EXTRA_OUTPUT extra. Take that file
* and move it into the instance folder.
*/
String path = intent.getStringExtra(android.provider.MediaStore.EXTRA_OUTPUT);
fi = new File(path);
instanceFolder = formController.getInstanceFile().getParent();
s = instanceFolder + File.separator + System.currentTimeMillis() + ".jpg";
nf = new File(s);
if (!fi.renameTo(nf)) {
Timber.e("Failed to rename %s", fi.getAbsolutePath());
} else {
Timber.i("Renamed %s to %s", fi.getAbsolutePath(), nf.getAbsolutePath());
}
if (getCurrentViewIfODKView() != null) {
getCurrentViewIfODKView().setBinaryData(nf);
}
saveAnswersForCurrentScreen(DO_NOT_EVALUATE_CONSTRAINTS);
break;
case RequestCodes.IMAGE_CHOOSER:
/*
* We have a saved image somewhere, but we really want it to be in:
* /sdcard/odk/instances/[current instnace]/something.jpg so we move
* it there before inserting it into the content provider. Once the
* android image capture bug gets fixed, (read, we move on from
* Android 1.6) we want to handle images the audio and video
*/
showDialog(SAVING_IMAGE_DIALOG);
Runnable runnable = () -> saveChosenImage(intent.getData());
new Thread(runnable).start();
break;
case RequestCodes.AUDIO_CAPTURE:
case RequestCodes.VIDEO_CAPTURE:
Uri mediaUri = intent.getData();
saveAudioVideoAnswer(mediaUri);
String filePath = MediaUtils.getDataColumn(this, mediaUri, null, null);
if (filePath != null) {
new File(filePath).delete();
}
try {
getContentResolver().delete(mediaUri, null, null);
} catch (Exception e) {
Timber.e(e);
}
break;
case RequestCodes.AUDIO_CHOOSER:
case RequestCodes.VIDEO_CHOOSER:
saveAudioVideoAnswer(intent.getData());
break;
case RequestCodes.LOCATION_CAPTURE:
String sl = intent.getStringExtra(LOCATION_RESULT);
if (getCurrentViewIfODKView() != null) {
getCurrentViewIfODKView().setBinaryData(sl);
}
saveAnswersForCurrentScreen(DO_NOT_EVALUATE_CONSTRAINTS);
break;
case RequestCodes.GEOSHAPE_CAPTURE:
String gshr = intent.getStringExtra(GEOSHAPE_RESULTS);
if (getCurrentViewIfODKView() != null) {
getCurrentViewIfODKView().setBinaryData(gshr);
}
saveAnswersForCurrentScreen(DO_NOT_EVALUATE_CONSTRAINTS);
break;
case RequestCodes.GEOTRACE_CAPTURE:
String traceExtra = intent.getStringExtra(GEOTRACE_RESULTS);
if (getCurrentViewIfODKView() != null) {
getCurrentViewIfODKView().setBinaryData(traceExtra);
}
saveAnswersForCurrentScreen(DO_NOT_EVALUATE_CONSTRAINTS);
break;
case RequestCodes.BEARING_CAPTURE:
String bearing = intent.getStringExtra(BEARING_RESULT);
if (getCurrentViewIfODKView() != null) {
getCurrentViewIfODKView().setBinaryData(bearing);
}
saveAnswersForCurrentScreen(DO_NOT_EVALUATE_CONSTRAINTS);
break;
case RequestCodes.HIERARCHY_ACTIVITY:
// refresh
break;
}
refreshCurrentView();
}
use of org.odk.collect.android.logic.FormController in project collect by opendatakit.
the class FormEntryActivity method removeTempInstance.
// Cleanup when user exits a form without saving
private void removeTempInstance() {
FormController formController = getFormController();
if (formController != null && formController.getInstanceFile() != null) {
SaveToDiskTask.removeSavepointFiles(formController.getInstanceFile().getName());
}
// if it's not already saved, erase everything
if (!InstancesDaoHelper.isInstanceAvailable(getAbsoluteInstancePath())) {
// delete media first
String instanceFolder = formController.getInstanceFile().getParent();
Timber.i("Attempting to delete: %s", instanceFolder);
File file = formController.getInstanceFile().getParentFile();
int images = MediaUtils.deleteImagesInFolderFromMediaProvider(file);
int audio = MediaUtils.deleteAudioInFolderFromMediaProvider(file);
int video = MediaUtils.deleteVideoInFolderFromMediaProvider(file);
Timber.i("Removed from content providers: %d image files, %d audio files and %d audio files.", images, audio, video);
FileUtils.purgeMediaPath(instanceFolder);
}
}
use of org.odk.collect.android.logic.FormController in project collect by opendatakit.
the class FormHierarchyActivity method refreshView.
public void refreshView() {
try {
FormController formController = Collect.getInstance().getFormController();
// Record the current index so we can return to the same place if the user hits 'back'.
currentIndex = formController.getFormIndex();
// If we're not at the first level, we're inside a repeated group so we want to only
// display
// everything enclosed within that group.
String contextGroupRef = "";
formList = new ArrayList<HierarchyElement>();
// node to display.
if (formController.getEvent() == FormEntryController.EVENT_REPEAT) {
contextGroupRef = formController.getFormIndex().getReference().toString(true);
formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
} else {
FormIndex startTest = formController.stepIndexOut(currentIndex);
// beginning.
while (startTest != null && formController.getEvent(startTest) == FormEntryController.EVENT_GROUP) {
startTest = formController.stepIndexOut(startTest);
}
if (startTest == null) {
// check to see if the question is at the first level of the hierarchy. If it
// is,
// display the root level from the beginning.
formController.jumpToIndex(FormIndex.createBeginningOfFormIndex());
} else {
// otherwise we're at a repeated group
formController.jumpToIndex(startTest);
}
// beginning
if (formController.getEvent() == FormEntryController.EVENT_REPEAT) {
contextGroupRef = formController.getFormIndex().getReference().toString(true);
formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
}
}
int event = formController.getEvent();
if (event == FormEntryController.EVENT_BEGINNING_OF_FORM) {
// The beginning of form has no valid prompt to display.
formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
contextGroupRef = formController.getFormIndex().getReference().getParentRef().toString(true);
path.setVisibility(View.GONE);
jumpPreviousButton.setEnabled(false);
} else {
path.setVisibility(View.VISIBLE);
path.setText(getCurrentPath());
jumpPreviousButton.setEnabled(true);
}
// Refresh the current event in case we did step forward.
event = formController.getEvent();
// Big change from prior implementation:
//
// The ref strings now include the instance number designations
// i.e., [0], [1], etc. of the repeat groups (and also [1] for
// non-repeat elements).
//
// The contextGroupRef is now also valid for the top-level form.
//
// The repeatGroupRef is null if we are not skipping a repeat
// section.
//
String repeatGroupRef = null;
event_search: while (event != FormEntryController.EVENT_END_OF_FORM) {
// get the ref to this element
String currentRef = formController.getFormIndex().getReference().toString(true);
// retrieve the current group
String curGroup = (repeatGroupRef == null) ? contextGroupRef : repeatGroupRef;
if (!currentRef.startsWith(curGroup)) {
// We have left the current group
if (repeatGroupRef == null) {
// We are done.
break;
} else {
// exit the inner repeat group
repeatGroupRef = null;
}
}
if (repeatGroupRef != null) {
// We're in a repeat group within the one we want to list
// skip this question/group/repeat and move to the next index.
event = formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
continue;
}
switch(event) {
case FormEntryController.EVENT_QUESTION:
FormEntryPrompt fp = formController.getQuestionPrompt();
String label = fp.getLongText();
if (!fp.isReadOnly() || (label != null && label.length() > 0)) {
// show the question if it is an editable field.
// or if it is read-only and the label is not blank.
String answerDisplay = FormEntryPromptUtils.getAnswerText(fp, this, formController);
formList.add(new HierarchyElement(FormEntryPromptUtils.markQuestionIfIsRequired(label, fp.isRequired()), answerDisplay, null, Color.WHITE, QUESTION, fp.getIndex()));
}
break;
case FormEntryController.EVENT_GROUP:
// ignore group events
break;
case FormEntryController.EVENT_PROMPT_NEW_REPEAT:
// ignore it.
break;
case FormEntryController.EVENT_REPEAT:
FormEntryCaption fc = formController.getCaptionPrompt();
// push this repeat onto the stack.
repeatGroupRef = currentRef;
if (fc.getMultiplicity() == 0) {
// Display the repeat header for the group.
HierarchyElement group = new HierarchyElement(fc.getLongText(), null, ContextCompat.getDrawable(getApplicationContext(), R.drawable.expander_ic_minimized), Color.WHITE, COLLAPSED, fc.getIndex());
formList.add(group);
}
String repeatLabel = mIndent + fc.getLongText();
if (fc.getFormElement().getChildren().size() == 1 && fc.getFormElement().getChild(0) instanceof GroupDef) {
formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
FormEntryCaption fc2 = formController.getCaptionPrompt();
if (fc2.getLongText() != null) {
repeatLabel = fc2.getLongText();
}
}
repeatLabel += " (" + (fc.getMultiplicity() + 1) + ")";
// Add this group name to the drop down list for this repeating group.
HierarchyElement h = formList.get(formList.size() - 1);
h.addChild(new HierarchyElement(repeatLabel, null, null, Color.WHITE, CHILD, fc.getIndex()));
break;
}
event = formController.stepToNextEvent(FormController.STEP_INTO_GROUP);
}
HierarchyListAdapter itla = new HierarchyListAdapter(this);
itla.setListItems(formList);
listView.setAdapter(itla);
// set the controller back to the current index in case the user hits 'back'
formController.jumpToIndex(currentIndex);
} catch (Exception e) {
Timber.e(e);
createErrorDialog(e.getMessage());
}
}
use of org.odk.collect.android.logic.FormController in project collect by opendatakit.
the class SaveToDiskTask method doInBackground.
/**
* Initialize {@link FormEntryController} with {@link org.javarosa.core.model.FormDef} from binary or from XML. If
* given
* an instance, it will be used to fill the {@link org.javarosa.core.model.FormDef}.
*/
@Override
protected SaveResult doInBackground(Void... nothing) {
SaveResult saveResult = new SaveResult();
FormController formController = Collect.getInstance().getFormController();
publishProgress(Collect.getInstance().getString(R.string.survey_saving_validating_message));
try {
int validateStatus = formController.validateAnswers(markCompleted);
if (validateStatus != FormEntryController.ANSWER_OK) {
// validation failed, pass specific failure
saveResult.setSaveResult(validateStatus, markCompleted);
return saveResult;
}
} catch (Exception e) {
Timber.e(e);
// SCTO-825
// that means that we have a bad design
// save the exception to be used in the error dialog.
saveResult.setSaveErrorMessage(e.getMessage());
saveResult.setSaveResult(SAVE_ERROR, markCompleted);
return saveResult;
}
// check if the "Cancel" was hit and exit.
if (isCancelled()) {
return null;
}
if (markCompleted) {
formController.postProcessInstance();
}
Collect.getInstance().getActivityLogger().logInstanceAction(this, "save", Boolean.toString(markCompleted));
// close all open databases of external data.
Collect.getInstance().getExternalDataManager().close();
// if there is a meta/instanceName field, be sure we are using the latest value
// just in case the validate somehow triggered an update.
String updatedSaveName = formController.getSubmissionMetadata().instanceName;
if (updatedSaveName != null) {
instanceName = updatedSaveName;
}
try {
exportData(markCompleted);
if (formController.getInstanceFile() != null) {
removeSavepointFiles(formController.getInstanceFile().getName());
}
saveResult.setSaveResult(save ? SAVED_AND_EXIT : SAVED, markCompleted);
} catch (EncryptionException e) {
saveResult.setSaveErrorMessage(e.getMessage());
saveResult.setSaveResult(ENCRYPTION_ERROR, markCompleted);
} catch (Exception e) {
Timber.e(e);
saveResult.setSaveErrorMessage(e.getMessage());
saveResult.setSaveResult(SAVE_ERROR, markCompleted);
}
return saveResult;
}
Aggregations