Search in sources :

Example 1 with FormLoaderTask

use of org.odk.collect.android.tasks.FormLoaderTask in project collect by opendatakit.

the class FormEntryActivity method onDestroy.

@Override
protected void onDestroy() {
    if (formLoaderTask != null) {
        formLoaderTask.setFormLoaderListener(null);
        // but only if it's done, otherwise the thread never returns
        if (formLoaderTask.getStatus() == AsyncTask.Status.FINISHED) {
            FormLoaderTask t = formLoaderTask;
            formLoaderTask = null;
            t.cancel(true);
            t.destroy();
        }
    }
    if (saveToDiskTask != null) {
        saveToDiskTask.setFormSavedListener(null);
        // lives on and retains the FEC in memory.
        if (saveToDiskTask.getStatus() == AsyncTask.Status.FINISHED) {
            saveToDiskTask.cancel(true);
            saveToDiskTask = null;
        }
    }
    releaseOdkView();
    formDefCacheCompositeDisposable.dispose();
    super.onDestroy();
}
Also used : FormLoaderTask(org.odk.collect.android.tasks.FormLoaderTask)

Example 2 with FormLoaderTask

use of org.odk.collect.android.tasks.FormLoaderTask in project collect by opendatakit.

the class FormEntryActivity method loadingComplete.

/**
 * loadingComplete() is called by FormLoaderTask once it has finished
 * loading a form.
 */
@Override
public void loadingComplete(FormLoaderTask task, FormDef formDef) {
    dismissDialog(PROGRESS_DIALOG);
    final FormController formController = task.getFormController();
    // these are bogus if
    int requestCode = task.getRequestCode();
    // pendingActivityResult is
    // false
    int resultCode = task.getResultCode();
    Intent intent = task.getIntent();
    formLoaderTask.setFormLoaderListener(null);
    FormLoaderTask t = formLoaderTask;
    formLoaderTask = null;
    t.cancel(true);
    t.destroy();
    Collect.getInstance().setFormController(formController);
    supportInvalidateOptionsMenu();
    Collect.getInstance().setExternalDataManager(task.getExternalDataManager());
    // Set the language if one has already been set in the past
    String[] languageTest = formController.getLanguages();
    if (languageTest != null) {
        String defaultLanguage = formController.getLanguage();
        String newLanguage = FormsDaoHelper.getFormLanguage(formPath);
        long start = System.currentTimeMillis();
        Timber.i("calling formController.setLanguage");
        try {
            formController.setLanguage(newLanguage);
        } catch (Exception e) {
            // if somehow we end up with a bad language, set it to the default
            Timber.e("Ended up with a bad language. %s", newLanguage);
            formController.setLanguage(defaultLanguage);
        }
        Timber.i("Done in %.3f seconds.", (System.currentTimeMillis() - start) / 1000F);
    }
    boolean pendingActivityResult = task.hasPendingActivityResult();
    if (pendingActivityResult) {
        // set the current view to whatever group we were at...
        refreshCurrentView();
        // process the pending activity request...
        onActivityResult(requestCode, resultCode, intent);
        return;
    }
    // it can be a normal flow for a pending activity result to restore from
    // a savepoint
    // (the call flow handled by the above if statement). For all other use
    // cases, the
    // user should be notified, as it means they wandered off doing other
    // things then
    // returned to ODK Collect and chose Edit Saved Form, but that the
    // savepoint for that
    // form is newer than the last saved version of their form data.
    boolean hasUsedSavepoint = task.hasUsedSavepoint();
    if (hasUsedSavepoint) {
        runOnUiThread(() -> ToastUtils.showLongToast(R.string.savepoint_used));
    }
    // Set saved answer path
    if (formController.getInstanceFile() == null) {
        // Create new answer folder.
        String time = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.ENGLISH).format(Calendar.getInstance().getTime());
        String file = formPath.substring(formPath.lastIndexOf('/') + 1, formPath.lastIndexOf('.'));
        String path = Collect.INSTANCES_PATH + File.separator + file + "_" + time;
        if (FileUtils.createFolder(path)) {
            File instanceFile = new File(path + File.separator + file + "_" + time + ".xml");
            formController.setInstanceFile(instanceFile);
        }
        formController.getTimerLogger().logTimerEvent(TimerLogger.EventTypes.FORM_START, 0, null, false, true);
    } else {
        Intent reqIntent = getIntent();
        boolean showFirst = reqIntent.getBooleanExtra("start", false);
        formController.getTimerLogger().logTimerEvent(TimerLogger.EventTypes.FORM_RESUME, 0, null, false, true);
        if (!showFirst) {
            if (!allowMovingBackwards) {
                FormIndex formIndex = SaveFormIndexTask.loadFormIndexFromFile();
                if (formIndex != null) {
                    formController.jumpToIndex(formIndex);
                    refreshCurrentView();
                    return;
                }
            }
            String formMode = reqIntent.getStringExtra(ApplicationConstants.BundleKeys.FORM_MODE);
            if (formMode == null || ApplicationConstants.FormModes.EDIT_SAVED.equalsIgnoreCase(formMode)) {
                startActivity(new Intent(this, EditFormHierarchyActivity.class));
                // so we don't show the intro screen before jumping to the hierarchy
                return;
            } else {
                if (ApplicationConstants.FormModes.VIEW_SENT.equalsIgnoreCase(formMode)) {
                    startActivity(new Intent(this, ViewFormHierarchyActivity.class));
                }
                finish();
            }
        }
    }
    refreshCurrentView();
    if (formDef != null) {
        final File cachedFormDefFile = FormDefCache.getCacheFile(new File(formPath));
        if (cachedFormDefFile.exists()) {
            Timber.i("FormDef %s is already in the cache", cachedFormDefFile.toString());
        } else {
            Disposable formDefCacheDisposable = writeCacheAsync(formDef, cachedFormDefFile).subscribe(() -> {
            }, Timber::e);
            formDefCacheCompositeDisposable.add(formDefCacheDisposable);
        }
    }
}
Also used : FormController(org.odk.collect.android.logic.FormController) CompositeDisposable(io.reactivex.disposables.CompositeDisposable) Disposable(io.reactivex.disposables.Disposable) Timber(timber.log.Timber) Intent(android.content.Intent) FailedConstraint(org.odk.collect.android.logic.FormController.FailedConstraint) GDriveConnectionException(org.odk.collect.android.exception.GDriveConnectionException) JavaRosaException(org.odk.collect.android.exception.JavaRosaException) FormLoaderTask(org.odk.collect.android.tasks.FormLoaderTask) FormIndex(org.javarosa.core.model.FormIndex) SimpleDateFormat(java.text.SimpleDateFormat) File(java.io.File)

Example 3 with FormLoaderTask

use of org.odk.collect.android.tasks.FormLoaderTask in project collect by opendatakit.

the class FormEntryActivity method onCreate.

/**
 * Called when the activity is first created.
 */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // external intent
    try {
        Collect.createODKDirs();
    } catch (RuntimeException e) {
        createErrorDialog(e.getMessage(), EXIT);
        return;
    }
    setContentView(R.layout.form_entry);
    errorMessage = null;
    beenSwiped = false;
    alertDialog = null;
    currentView = null;
    inAnimation = null;
    outAnimation = null;
    gestureDetector = new GestureDetector(this, this);
    questionHolder = findViewById(R.id.questionholder);
    initToolbar();
    nextButton = findViewById(R.id.form_forward_button);
    nextButton.setOnClickListener(v -> {
        beenSwiped = true;
        showNextView();
    });
    backButton = findViewById(R.id.form_back_button);
    backButton.setOnClickListener(v -> {
        beenSwiped = true;
        showPreviousView();
    });
    String startingXPath = null;
    String waitingXPath = null;
    String instancePath = null;
    boolean newForm = true;
    autoSaved = false;
    allowMovingBackwards = (boolean) AdminSharedPreferences.getInstance().get(KEY_MOVING_BACKWARDS);
    if (savedInstanceState != null) {
        state = savedInstanceState;
        if (savedInstanceState.containsKey(KEY_FORMPATH)) {
            formPath = savedInstanceState.getString(KEY_FORMPATH);
        }
        if (savedInstanceState.containsKey(KEY_INSTANCEPATH)) {
            instancePath = savedInstanceState.getString(KEY_INSTANCEPATH);
        }
        if (savedInstanceState.containsKey(KEY_XPATH)) {
            startingXPath = savedInstanceState.getString(KEY_XPATH);
            Timber.i("startingXPath is: %s", startingXPath);
        }
        if (savedInstanceState.containsKey(KEY_XPATH_WAITING_FOR_DATA)) {
            waitingXPath = savedInstanceState.getString(KEY_XPATH_WAITING_FOR_DATA);
            Timber.i("waitingXPath is: %s", waitingXPath);
        }
        if (savedInstanceState.containsKey(NEWFORM)) {
            newForm = savedInstanceState.getBoolean(NEWFORM, true);
        }
        if (savedInstanceState.containsKey(KEY_ERROR)) {
            errorMessage = savedInstanceState.getString(KEY_ERROR);
        }
        saveName = savedInstanceState.getString(KEY_SAVE_NAME);
        if (savedInstanceState.containsKey(KEY_AUTO_SAVED)) {
            autoSaved = savedInstanceState.getBoolean(KEY_AUTO_SAVED);
        }
    }
    // Dialogs mid form just disappear on rotation.
    if (errorMessage != null) {
        createErrorDialog(errorMessage, EXIT);
        return;
    }
    // Check to see if this is a screen flip or a new form load.
    Object data = getLastCustomNonConfigurationInstance();
    if (data instanceof FormLoaderTask) {
        formLoaderTask = (FormLoaderTask) data;
    } else if (data instanceof SaveToDiskTask) {
        saveToDiskTask = (SaveToDiskTask) data;
    } else if (data == null) {
        if (!newForm) {
            if (getFormController() != null) {
                refreshCurrentView();
            } else {
                Timber.w("Reloading form and restoring state.");
                // we need to launch the form loader to load the form
                // controller...
                formLoaderTask = new FormLoaderTask(instancePath, startingXPath, waitingXPath);
                Collect.getInstance().getActivityLogger().logAction(this, "formReloaded", formPath);
                // TODO: this doesn' work (dialog does not get removed):
                // showDialog(PROGRESS_DIALOG);
                // show dialog before we execute...
                formLoaderTask.execute(formPath);
            }
            return;
        }
        // Not a restart from a screen orientation change (or other).
        Collect.getInstance().setFormController(null);
        supportInvalidateOptionsMenu();
        Intent intent = getIntent();
        if (intent != null) {
            Uri uri = intent.getData();
            String uriMimeType = null;
            if (uri != null) {
                uriMimeType = getContentResolver().getType(uri);
            }
            if (uriMimeType == null && intent.hasExtra(EXTRA_TESTING_PATH)) {
                formPath = intent.getStringExtra(EXTRA_TESTING_PATH);
            } else if (uriMimeType != null && uriMimeType.equals(InstanceColumns.CONTENT_ITEM_TYPE)) {
                // get the formId and version for this instance...
                FormInfo formInfo = ContentResolverHelper.getFormDetails(uri);
                if (formInfo == null) {
                    createErrorDialog(getString(R.string.bad_uri, uri), EXIT);
                    return;
                }
                instancePath = formInfo.getInstancePath();
                Collect.getInstance().getActivityLogger().logAction(this, "instanceLoaded", instancePath);
                String jrFormId = formInfo.getFormID();
                String jrVersion = formInfo.getFormVersion();
                String[] selectionArgs;
                String selection;
                if (jrVersion == null) {
                    selectionArgs = new String[] { jrFormId };
                    selection = FormsColumns.JR_FORM_ID + "=? AND " + FormsColumns.JR_VERSION + " IS NULL";
                } else {
                    selectionArgs = new String[] { jrFormId, jrVersion };
                    selection = FormsColumns.JR_FORM_ID + "=? AND " + FormsColumns.JR_VERSION + "=?";
                }
                int formCount = FormsDaoHelper.getFormsCount(selection, selectionArgs);
                if (formCount < 1) {
                    createErrorDialog(getString(R.string.parent_form_not_present, jrFormId) + ((jrVersion == null) ? "" : "\n" + getString(R.string.version) + " " + jrVersion), EXIT);
                    return;
                } else {
                    formPath = FormsDaoHelper.getFormPath(selection, selectionArgs);
                    // database to fix it.
                    if (formCount > 1) {
                        createErrorDialog(getString(R.string.survey_multiple_forms_error), EXIT);
                        return;
                    }
                }
            } else if (uriMimeType != null && uriMimeType.equals(FormsColumns.CONTENT_ITEM_TYPE)) {
                formPath = ContentResolverHelper.getFormPath(uri);
                if (formPath == null) {
                    createErrorDialog(getString(R.string.bad_uri, uri), EXIT);
                    return;
                } else {
                    // This is the fill-blank-form code path.
                    // See if there is a savepoint for this form that
                    // has never been
                    // explicitly saved
                    // by the user. If there is, open this savepoint
                    // (resume this filled-in
                    // form).
                    // Savepoints for forms that were explicitly saved
                    // will be recovered
                    // when that
                    // explicitly saved instance is edited via
                    // edit-saved-form.
                    final String filePrefix = formPath.substring(formPath.lastIndexOf('/') + 1, formPath.lastIndexOf('.')) + "_";
                    final String fileSuffix = ".xml.save";
                    File cacheDir = new File(Collect.CACHE_PATH);
                    File[] files = cacheDir.listFiles(pathname -> {
                        String name = pathname.getName();
                        return name.startsWith(filePrefix) && name.endsWith(fileSuffix);
                    });
                    // explicitly saved by the user...
                    for (File candidate : files) {
                        String instanceDirName = candidate.getName().substring(0, candidate.getName().length() - fileSuffix.length());
                        File instanceDir = new File(Collect.INSTANCES_PATH + File.separator + instanceDirName);
                        File instanceFile = new File(instanceDir, instanceDirName + ".xml");
                        if (instanceDir.exists() && instanceDir.isDirectory() && !instanceFile.exists()) {
                            // yes! -- use this savepoint file
                            instancePath = instanceFile.getAbsolutePath();
                            break;
                        }
                    }
                }
            } else {
                Timber.e("Unrecognized URI: %s", uri);
                createErrorDialog(getString(R.string.unrecognized_uri, uri), EXIT);
                return;
            }
            formLoaderTask = new FormLoaderTask(instancePath, null, null);
            Collect.getInstance().getActivityLogger().logAction(this, "formLoaded", formPath);
            showDialog(PROGRESS_DIALOG);
            // show dialog before we execute...
            formLoaderTask.execute(formPath);
        }
    }
}
Also used : FormInfo(org.odk.collect.android.logic.FormInfo) GestureDetector(android.view.GestureDetector) Intent(android.content.Intent) SaveToDiskTask(org.odk.collect.android.tasks.SaveToDiskTask) Uri(android.net.Uri) File(java.io.File) FormLoaderTask(org.odk.collect.android.tasks.FormLoaderTask)

Example 4 with FormLoaderTask

use of org.odk.collect.android.tasks.FormLoaderTask in project collect by opendatakit.

the class FormEntryActivity method onResume.

@Override
protected void onResume() {
    super.onResume();
    String navigation = (String) GeneralSharedPreferences.getInstance().get(PreferenceKeys.KEY_NAVIGATION);
    showNavigationButtons = navigation.contains(PreferenceKeys.NAVIGATION_BUTTONS);
    backButton.setVisibility(showNavigationButtons ? View.VISIBLE : View.GONE);
    nextButton.setVisibility(showNavigationButtons ? View.VISIBLE : View.GONE);
    if (errorMessage != null) {
        if (alertDialog != null && !alertDialog.isShowing()) {
            createErrorDialog(errorMessage, EXIT);
        } else {
            return;
        }
    }
    FormController formController = getFormController();
    Collect.getInstance().getActivityLogger().open();
    if (formLoaderTask != null) {
        formLoaderTask.setFormLoaderListener(this);
        if (formController == null && formLoaderTask.getStatus() == AsyncTask.Status.FINISHED) {
            FormController fec = formLoaderTask.getFormController();
            if (fec != null) {
                loadingComplete(formLoaderTask, formLoaderTask.getFormDef());
            } else {
                dismissDialog(PROGRESS_DIALOG);
                FormLoaderTask t = formLoaderTask;
                formLoaderTask = null;
                t.cancel(true);
                t.destroy();
                // there is no formController -- fire MainMenu activity?
                startActivity(new Intent(this, MainMenuActivity.class));
            }
        }
    } else {
        if (formController == null) {
            // there is no formController -- fire MainMenu activity?
            startActivity(new Intent(this, MainMenuActivity.class));
            return;
        } else {
            refreshCurrentView();
        }
    }
    if (saveToDiskTask != null) {
        saveToDiskTask.setFormSavedListener(this);
    }
}
Also used : FormController(org.odk.collect.android.logic.FormController) Intent(android.content.Intent) FormLoaderTask(org.odk.collect.android.tasks.FormLoaderTask)

Example 5 with FormLoaderTask

use of org.odk.collect.android.tasks.FormLoaderTask in project collect by opendatakit.

the class FormEntryActivity method onCreateDialog.

/**
 * We use Android's dialog management for loading/saving progress dialogs
 */
@Override
protected Dialog onCreateDialog(int id) {
    switch(id) {
        case PROGRESS_DIALOG:
            Collect.getInstance().getActivityLogger().logInstanceAction(this, "onCreateDialog.PROGRESS_DIALOG", "show");
            progressDialog = new ProgressDialog(this);
            DialogInterface.OnClickListener loadingButtonListener = new DialogInterface.OnClickListener() {

                @Override
                public void onClick(DialogInterface dialog, int which) {
                    Collect.getInstance().getActivityLogger().logInstanceAction(this, "onCreateDialog.PROGRESS_DIALOG", "cancel");
                    dialog.dismiss();
                    if (formLoaderTask != null) {
                        formLoaderTask.setFormLoaderListener(null);
                        FormLoaderTask t = formLoaderTask;
                        formLoaderTask = null;
                        t.cancel(true);
                        t.destroy();
                    }
                    finish();
                }
            };
            progressDialog.setTitle(getString(R.string.loading_form));
            progressDialog.setMessage(getString(R.string.please_wait));
            progressDialog.setIndeterminate(true);
            progressDialog.setCancelable(false);
            progressDialog.setButton(getString(R.string.cancel_loading_form), loadingButtonListener);
            return progressDialog;
        case SAVING_DIALOG:
            Collect.getInstance().getActivityLogger().logInstanceAction(this, "onCreateDialog.SAVING_DIALOG", "show");
            progressDialog = new ProgressDialog(this);
            progressDialog.setTitle(getString(R.string.saving_form));
            progressDialog.setMessage(getString(R.string.please_wait));
            progressDialog.setIndeterminate(true);
            progressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {

                @Override
                public void onDismiss(DialogInterface dialog) {
                    Collect.getInstance().getActivityLogger().logInstanceAction(this, "onCreateDialog.SAVING_DIALOG", "OnDismissListener");
                    cancelSaveToDiskTask();
                }
            });
            return progressDialog;
        case SAVING_IMAGE_DIALOG:
            progressDialog = new ProgressDialog(this);
            progressDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
            progressDialog.setMessage(getString(R.string.please_wait));
            progressDialog.setCancelable(false);
            return progressDialog;
    }
    return null;
}
Also used : DialogInterface(android.content.DialogInterface) OnClickListener(android.view.View.OnClickListener) ProgressDialog(android.app.ProgressDialog) FormLoaderTask(org.odk.collect.android.tasks.FormLoaderTask)

Aggregations

FormLoaderTask (org.odk.collect.android.tasks.FormLoaderTask)6 Intent (android.content.Intent)3 FormController (org.odk.collect.android.logic.FormController)3 File (java.io.File)2 ProgressDialog (android.app.ProgressDialog)1 DialogInterface (android.content.DialogInterface)1 Uri (android.net.Uri)1 GestureDetector (android.view.GestureDetector)1 OnClickListener (android.view.View.OnClickListener)1 CompositeDisposable (io.reactivex.disposables.CompositeDisposable)1 Disposable (io.reactivex.disposables.Disposable)1 IOException (java.io.IOException)1 SimpleDateFormat (java.text.SimpleDateFormat)1 ExecutionException (java.util.concurrent.ExecutionException)1 FormDef (org.javarosa.core.model.FormDef)1 FormIndex (org.javarosa.core.model.FormIndex)1 GDriveConnectionException (org.odk.collect.android.exception.GDriveConnectionException)1 JavaRosaException (org.odk.collect.android.exception.JavaRosaException)1 FormLoaderListener (org.odk.collect.android.listeners.FormLoaderListener)1 FailedConstraint (org.odk.collect.android.logic.FormController.FailedConstraint)1