Search in sources :

Example 1 with InstancesRepositoryProvider

use of org.odk.collect.android.utilities.InstancesRepositoryProvider in project collect by opendatakit.

the class QuitFormDialogFragment method onCreateDialog.

@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
    super.onCreateDialog(savedInstanceState);
    String title = formSaveViewModel.getFormName() == null ? getActivity().getString(R.string.no_form_loaded) : formSaveViewModel.getFormName();
    List<IconMenuItem> items;
    if (settingsProvider.getProtectedSettings().getBoolean(ProtectedProjectKeys.KEY_SAVE_MID)) {
        items = ImmutableList.of(new IconMenuItem(R.drawable.ic_save, R.string.keep_changes), new IconMenuItem(R.drawable.ic_delete, R.string.do_not_save));
    } else {
        items = ImmutableList.of(new IconMenuItem(R.drawable.ic_delete, R.string.do_not_save));
    }
    ListView listView = DialogUtils.createActionListView(getActivity());
    final IconMenuListAdapter adapter = new IconMenuListAdapter(getActivity(), items);
    listView.setAdapter(adapter);
    listView.setOnItemClickListener((parent, view, position, id) -> {
        IconMenuItem item = (IconMenuItem) adapter.getItem(position);
        if (item.getTextResId() == R.string.keep_changes) {
            if (listener != null) {
                listener.onSaveChangesClicked();
            }
        } else {
            formSaveViewModel.ignoreChanges();
            String action = getActivity().getIntent().getAction();
            if (Intent.ACTION_PICK.equals(action) || Intent.ACTION_EDIT.equals(action)) {
                // caller is waiting on a picked form
                Uri uri = null;
                String path = formSaveViewModel.getAbsoluteInstancePath();
                if (path != null) {
                    Instance instance = new InstancesRepositoryProvider(requireContext()).get().getOneByPath(path);
                    if (instance != null) {
                        uri = InstancesContract.getUri(currentProjectProvider.getCurrentProject().getUuid(), instance.getDbId());
                    }
                }
                if (uri != null) {
                    getActivity().setResult(RESULT_OK, new Intent().setData(uri));
                }
            }
            getActivity().finish();
        }
        if (getDialog() != null) {
            getDialog().dismiss();
        }
    });
    return new MaterialAlertDialogBuilder(getActivity()).setTitle(getString(R.string.quit_application, title)).setNegativeButton(getActivity().getString(R.string.do_not_exit), (dialog, id) -> {
        dialog.cancel();
        dismiss();
    }).setView(listView).create();
}
Also used : InstancesRepositoryProvider(org.odk.collect.android.utilities.InstancesRepositoryProvider) ListView(android.widget.ListView) Instance(org.odk.collect.forms.instances.Instance) IconMenuListAdapter(org.odk.collect.android.adapters.IconMenuListAdapter) IconMenuItem(org.odk.collect.android.adapters.model.IconMenuItem) Intent(android.content.Intent) Uri(android.net.Uri) MaterialAlertDialogBuilder(com.google.android.material.dialog.MaterialAlertDialogBuilder) NonNull(androidx.annotation.NonNull)

Example 2 with InstancesRepositoryProvider

use of org.odk.collect.android.utilities.InstancesRepositoryProvider in project collect by opendatakit.

the class SaveFormToDisk method exportData.

/**
 * Write's the data to the sdcard, and updates the instances content provider.
 * In theory we don't have to write to disk, and this is where you'd add
 * other methods.
 */
private void exportData(boolean markCompleted, FormSaver.ProgressListener progressListener) throws IOException, EncryptionException {
    FormController formController = Collect.getInstance().getFormController();
    progressListener.onProgressUpdate(getLocalizedString(Collect.getInstance(), R.string.survey_saving_collecting_message));
    ByteArrayPayload payload = formController.getFilledInFormXml();
    // write out xml
    String instancePath = formController.getInstanceFile().getAbsolutePath();
    for (String fileName : tempFiles) {
        mediaUtils.deleteMediaFile(fileName);
    }
    progressListener.onProgressUpdate(getLocalizedString(Collect.getInstance(), R.string.survey_saving_saving_message));
    writeFile(payload, instancePath);
    // Write last-saved instance
    String lastSavedPath = formController.getLastSavedPath();
    writeFile(payload, lastSavedPath);
    // update the uri. We have exported the reloadable instance, so update status...
    // Since we saved a reloadable instance, it is flagged as re-openable so that if any error
    // occurs during the packaging of the data for the server fails (e.g., encryption),
    // we can still reopen the filled-out form and re-save it at a later time.
    updateInstanceDatabase(true, true);
    if (markCompleted) {
        // now see if the packaging of the data for the server would make it
        // non-reopenable (e.g., encryption or other fraction of the form).
        boolean canEditAfterCompleted = formController.isSubmissionEntireForm();
        boolean isEncrypted = false;
        // build a submission.xml to hold the data being submitted
        // and (if appropriate) encrypt the files on the side
        // pay attention to the ref attribute of the submission profile...
        File instanceXml = formController.getInstanceFile();
        File submissionXml = new File(instanceXml.getParentFile(), "submission.xml");
        payload = formController.getSubmissionXml();
        // write out submission.xml -- the data to actually submit to aggregate
        progressListener.onProgressUpdate(getLocalizedString(Collect.getInstance(), R.string.survey_saving_finalizing_message));
        writeFile(payload, submissionXml.getAbsolutePath());
        // see if the form is encrypted and we can encrypt it...
        EncryptedFormInformation formInfo = EncryptionUtils.getEncryptedFormInformation(uri, formController.getSubmissionMetadata());
        if (formInfo != null) {
            // if we are encrypting, the form cannot be reopened afterward
            canEditAfterCompleted = false;
            // and encrypt the submission (this is a one-way operation)...
            progressListener.onProgressUpdate(getLocalizedString(Collect.getInstance(), R.string.survey_saving_encrypting_message));
            EncryptionUtils.generateEncryptedSubmission(instanceXml, submissionXml, formInfo);
            isEncrypted = true;
            analytics.logEvent(ENCRYPT_SUBMISSION, AnalyticsUtils.getFormHash(Collect.getInstance().getFormController()), "");
        }
        // At this point, we have:
        // 1. the saved original instanceXml,
        // 2. all the plaintext attachments
        // 2. the submission.xml that is the completed xml (whether encrypting or not)
        // 3. all the encrypted attachments if encrypting (isEncrypted = true).
        // 
        // NEXT:
        // 1. Update the instance database (with status complete).
        // 2. Overwrite the instanceXml with the submission.xml
        // and remove the plaintext attachments if encrypting
        updateInstanceDatabase(false, canEditAfterCompleted);
        if (!canEditAfterCompleted) {
            manageFilesAfterSavingEncryptedForm(instanceXml, submissionXml);
        } else {
            // (we don't need to delete and rename anything).
            if (!submissionXml.delete()) {
                String msg = "Error deleting " + submissionXml.getAbsolutePath() + " (instance is re-openable)";
                Timber.w(msg);
            }
        }
        // (anything not named instanceXml or anything not ending in .enc)
        if (isEncrypted) {
            InstancesRepository instancesRepository = new InstancesRepositoryProvider(Collect.getInstance()).get();
            Instance instance = instancesRepository.get(ContentUriHelper.getIdFromUri(uri));
            // Clear the geometry. Done outside of updateInstanceDatabase to avoid multiple
            // branches and because it has no knowledge of encryption status.
            instancesRepository.save(new Instance.Builder(instance).geometry(null).geometryType(null).build());
            ContentValues values = new ContentValues();
            values.put(DatabaseInstanceColumns.GEOMETRY, (String) null);
            values.put(DatabaseInstanceColumns.GEOMETRY_TYPE, (String) null);
            if (!EncryptionUtils.deletePlaintextFiles(instanceXml, new File(lastSavedPath))) {
                Timber.e("Error deleting plaintext files for %s", instanceXml.getAbsolutePath());
            }
        }
    }
}
Also used : FormController(org.odk.collect.android.javarosawrapper.FormController) ContentValues(android.content.ContentValues) InstancesRepositoryProvider(org.odk.collect.android.utilities.InstancesRepositoryProvider) ByteArrayPayload(org.javarosa.core.services.transport.payload.ByteArrayPayload) FormInstance(org.javarosa.core.model.instance.FormInstance) Instance(org.odk.collect.forms.instances.Instance) InstancesRepository(org.odk.collect.forms.instances.InstancesRepository) LocalizedApplicationKt.getLocalizedString(org.odk.collect.strings.localization.LocalizedApplicationKt.getLocalizedString) EncryptedFormInformation(org.odk.collect.android.utilities.EncryptionUtils.EncryptedFormInformation) RandomAccessFile(java.io.RandomAccessFile) File(java.io.File)

Example 3 with InstancesRepositoryProvider

use of org.odk.collect.android.utilities.InstancesRepositoryProvider in project collect by opendatakit.

the class InstanceUploaderTask method onPostExecute.

@Override
protected void onPostExecute(Outcome outcome) {
    synchronized (this) {
        if (outcome != null && stateListener != null) {
            if (outcome.authRequestingServer != null) {
                stateListener.authRequest(outcome.authRequestingServer, outcome.messagesByInstanceId);
            } else {
                stateListener.uploadingComplete(outcome.messagesByInstanceId);
                // Delete instances that were successfully sent and that need to be deleted
                // either because app-level auto-delete is enabled or because the form
                // specifies it.
                Set<String> instanceIds = outcome.messagesByInstanceId.keySet();
                boolean isFormAutoDeleteOptionEnabled;
                // the app preferences set for delete after submission
                if (deleteInstanceAfterSubmission != null) {
                    isFormAutoDeleteOptionEnabled = deleteInstanceAfterSubmission;
                } else {
                    isFormAutoDeleteOptionEnabled = settingsProvider.getUnprotectedSettings().getBoolean(ProjectKeys.KEY_DELETE_AFTER_SEND);
                }
                Stream<Instance> instancesToDelete = instanceIds.stream().map(id -> new InstancesRepositoryProvider(Collect.getInstance()).get().get(Long.parseLong(id))).filter(instance -> instance.getStatus().equals(Instance.STATUS_SUBMITTED)).filter(instance -> shouldFormBeDeleted(formsRepository, instance.getFormId(), instance.getFormVersion(), isFormAutoDeleteOptionEnabled));
                DeleteInstancesTask dit = new DeleteInstancesTask(instancesRepository, formsRepository);
                dit.execute(instancesToDelete.map(Instance::getDbId).toArray(Long[]::new));
            }
        }
    }
}
Also used : InstancesRepository(org.odk.collect.forms.instances.InstancesRepository) ProjectKeys(org.odk.collect.settings.keys.ProjectKeys) SettingsProvider(org.odk.collect.settings.SettingsProvider) Instance(org.odk.collect.forms.instances.Instance) AsyncTask(android.os.AsyncTask) InstanceUploaderListener(org.odk.collect.android.listeners.InstanceUploaderListener) InstanceUploaderUtils.shouldFormBeDeleted(org.odk.collect.android.utilities.InstanceUploaderUtils.shouldFormBeDeleted) Uri(android.net.Uri) Set(java.util.Set) HashMap(java.util.HashMap) InstancesRepositoryProvider(org.odk.collect.android.utilities.InstancesRepositoryProvider) FormsRepository(org.odk.collect.forms.FormsRepository) Stream(java.util.stream.Stream) Collect(org.odk.collect.android.application.Collect) InstancesRepositoryProvider(org.odk.collect.android.utilities.InstancesRepositoryProvider) Instance(org.odk.collect.forms.instances.Instance)

Example 4 with InstancesRepositoryProvider

use of org.odk.collect.android.utilities.InstancesRepositoryProvider in project collect by opendatakit.

the class FormEntryActivity method finishAndReturnInstance.

/**
 * Returns the instance that was just filled out to the calling activity, if
 * requested.
 */
private void finishAndReturnInstance() {
    String action = getIntent().getAction();
    if (Intent.ACTION_PICK.equals(action) || Intent.ACTION_EDIT.equals(action)) {
        // caller is waiting on a picked form
        Uri uri = null;
        String path = getAbsoluteInstancePath();
        if (path != null) {
            Instance instance = new InstancesRepositoryProvider(this).get().getOneByPath(path);
            if (instance != null) {
                uri = InstancesContract.getUri(currentProjectProvider.getCurrentProject().getUuid(), instance.getDbId());
            }
        }
        if (uri != null) {
            setResult(RESULT_OK, new Intent().setData(uri));
        }
    }
    finish();
}
Also used : InstancesRepositoryProvider(org.odk.collect.android.utilities.InstancesRepositoryProvider) Instance(org.odk.collect.forms.instances.Instance) Intent(android.content.Intent) Uri(android.net.Uri)

Example 5 with InstancesRepositoryProvider

use of org.odk.collect.android.utilities.InstancesRepositoryProvider in project collect by opendatakit.

the class FormEntryActivity method createViewForFormEnd.

/**
 * Creates the final screen in a form-filling interaction. Allows the user to set a display
 * name for the instance and to decide whether the form should be finalized or not. Presents
 * a button for saving and exiting.
 */
private View createViewForFormEnd(FormController formController) {
    if (formController.getSubmissionMetadata().instanceName != null) {
        saveName = formController.getSubmissionMetadata().instanceName;
    } else {
        // no meta/instanceName field in the form -- see if we have a
        // name for this instance from a previous save attempt...
        String uriMimeType = null;
        Uri instanceUri = getIntent().getData();
        if (instanceUri != null) {
            uriMimeType = getContentResolver().getType(instanceUri);
        }
        if (saveName == null && uriMimeType != null && uriMimeType.equals(InstancesContract.CONTENT_ITEM_TYPE)) {
            Instance instance = new InstancesRepositoryProvider(Collect.getInstance()).get().get(ContentUriHelper.getIdFromUri(instanceUri));
            if (instance != null) {
                saveName = instance.getDisplayName();
            }
        }
        if (saveName == null) {
            saveName = formSaveViewModel.getFormName();
        }
    }
    FormEndView endView = new FormEndView(this, formSaveViewModel.getFormName(), saveName, InstancesDaoHelper.isInstanceComplete(true, settingsProvider.getUnprotectedSettings().getBoolean(KEY_COMPLETED_DEFAULT)), new FormEndView.Listener() {

        @Override
        public void onSaveAsChanged(String saveAs) {
            // Seems like this is needed for rotation?
            saveName = saveAs;
        }

        @Override
        public void onSaveClicked(boolean markAsFinalized) {
            if (saveName.length() < 1) {
                showShortToast(FormEntryActivity.this, R.string.save_as_error);
            } else {
                formSaveViewModel.saveForm(getIntent().getData(), markAsFinalized, saveName, true);
            }
        }
    });
    if (!settingsProvider.getProtectedSettings().getBoolean(ProtectedProjectKeys.KEY_MARK_AS_FINALIZED)) {
        endView.findViewById(R.id.mark_finished).setVisibility(View.GONE);
    }
    if (formController.getSubmissionMetadata().instanceName != null) {
        // if instanceName is defined in form, this is the name -- no
        // revisions
        // display only the name, not the prompt, and disable edits
        endView.findViewById(R.id.save_form_as).setVisibility(View.GONE);
        endView.findViewById(R.id.save_name).setEnabled(false);
        endView.findViewById(R.id.save_name).setVisibility(View.VISIBLE);
    }
    // override the visibility settings based upon admin preferences
    if (!settingsProvider.getProtectedSettings().getBoolean(ProtectedProjectKeys.KEY_SAVE_AS)) {
        endView.findViewById(R.id.save_form_as).setVisibility(View.GONE);
        endView.findViewById(R.id.save_name).setVisibility(View.GONE);
    }
    if (showNavigationButtons) {
        updateNavigationButtonVisibility();
    }
    return endView;
}
Also used : InstancesRepositoryProvider(org.odk.collect.android.utilities.InstancesRepositoryProvider) Instance(org.odk.collect.forms.instances.Instance) FormEndView(org.odk.collect.android.formentry.FormEndView) Uri(android.net.Uri)

Aggregations

InstancesRepositoryProvider (org.odk.collect.android.utilities.InstancesRepositoryProvider)10 Instance (org.odk.collect.forms.instances.Instance)10 Uri (android.net.Uri)5 FormController (org.odk.collect.android.javarosawrapper.FormController)4 Intent (android.content.Intent)3 FormsRepositoryProvider (org.odk.collect.android.utilities.FormsRepositoryProvider)3 AsyncTask (android.os.AsyncTask)2 NonNull (androidx.annotation.NonNull)2 HashMap (java.util.HashMap)2 FormInstance (org.javarosa.core.model.instance.FormInstance)2 Form (org.odk.collect.forms.Form)2 InstancesRepository (org.odk.collect.forms.instances.InstancesRepository)2 LocalizedApplicationKt.getLocalizedString (org.odk.collect.strings.localization.LocalizedApplicationKt.getLocalizedString)2 BroadcastReceiver (android.content.BroadcastReceiver)1 ContentValues (android.content.ContentValues)1 Context (android.content.Context)1 DialogInterface (android.content.DialogInterface)1 BUTTON_NEGATIVE (android.content.DialogInterface.BUTTON_NEGATIVE)1 BUTTON_POSITIVE (android.content.DialogInterface.BUTTON_POSITIVE)1 IntentFilter (android.content.IntentFilter)1