package org.commcare.activities; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import org.commcare.CommCareApplication; import org.commcare.dalvik.R; import org.commcare.logging.AndroidLogger; import org.commcare.models.database.SqlStorage; import org.commcare.android.database.user.models.FormRecord; import org.commcare.preferences.CommCarePreferences; import org.commcare.preferences.CommCareServerPreferences; import org.commcare.tasks.DumpTask; import org.commcare.tasks.SendTask; import org.commcare.utils.FileUtil; import org.commcare.utils.StorageUtils; import org.commcare.views.ManagedUi; import org.commcare.views.UiElement; import org.commcare.views.dialogs.StandardAlertDialog; import org.commcare.views.dialogs.CustomProgressDialog; import org.commcare.views.notifications.NotificationMessageFactory; import org.commcare.views.notifications.NotificationMessageFactory.StockMessages; import org.javarosa.core.services.Logger; import org.javarosa.core.services.locale.Localization; import java.io.File; import java.util.Vector; /** * @author wspride */ @ManagedUi(R.layout.screen_form_dump) public class CommCareFormDumpActivity extends SessionAwareCommCareActivity<CommCareFormDumpActivity> { private static final String TAG = CommCareFormDumpActivity.class.getSimpleName(); public static final String DUMP_FORMS_ERROR = "DUMP_FORMS_ERROR"; @UiElement(value = R.id.screen_bulk_form_prompt, locale = "bulk.form.prompt") TextView txtDisplayPrompt; @UiElement(value = R.id.screen_bulk_form_dump, locale = "bulk.form.dump") Button btnDumpForms; @UiElement(value = R.id.screen_bulk_form_submit, locale = "bulk.form.submit") Button btnSubmitForms; @UiElement(value = R.id.screen_bulk_form_messages, locale = "bulk.form.messages") TextView txtInteractiveMessages; public static final String AIRPLANE_MODE_CATEGORY = "airplane-mode"; private static boolean acknowledgedRisk = false; public static final String EXTRA_FILE_DESTINATION = "ccodk_mia_filedest"; private int formsOnPhone; private int formsOnSD; @Override protected void onCreate(Bundle savedInstanceState) { final String url = this.getString(R.string.PostURL); super.onCreate(savedInstanceState); updateCounters(); btnSubmitForms.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { formsOnSD = getDumpFiles().length; Logger.log(AndroidLogger.TYPE_FORM_DUMP, "Send task found " + formsOnSD + " forms on the phone."); //if there're no forms to dump, just return if (formsOnSD == 0) { txtInteractiveMessages.setText(localize("bulk.form.no.unsynced.submit")); transplantStyle(txtInteractiveMessages, R.layout.template_text_notification_problem); return; } SharedPreferences settings = CommCareApplication.instance().getCurrentApp().getAppPreferences(); SendTask<CommCareFormDumpActivity> mSendTask = new SendTask<CommCareFormDumpActivity>( settings.getString(CommCareServerPreferences.PREFS_SUBMISSION_URL_KEY, url), getFolderPath()) { @Override protected void deliverResult(CommCareFormDumpActivity receiver, Boolean result) { if (result == Boolean.TRUE) { CommCareApplication.notificationManager().clearNotifications(AIRPLANE_MODE_CATEGORY); Intent i = new Intent(getIntent()); i.putExtra(AdvancedActionsActivity.KEY_NUMBER_DUMPED, formsOnSD); receiver.setResult(BULK_SEND_ID, i); Logger.log(AndroidLogger.TYPE_FORM_DUMP, "Successfully submitted " + formsOnSD + " forms."); receiver.finish(); } else { //assume that we've already set the error message, but make it look scary CommCareApplication.notificationManager().reportNotificationMessage(NotificationMessageFactory.message(StockMessages.Sync_AirplaneMode, AIRPLANE_MODE_CATEGORY)); receiver.updateCounters(); receiver.transplantStyle(txtInteractiveMessages, R.layout.template_text_notification_problem); } } @Override protected void deliverUpdate(CommCareFormDumpActivity receiver, String... update) { receiver.updateProgress(update[0], BULK_SEND_ID); receiver.txtInteractiveMessages.setText(update[0]); } @Override protected void deliverError(CommCareFormDumpActivity receiver, Exception e) { Logger.log(AndroidLogger.TYPE_FORM_DUMP, "Send failed with exception: " + e.getMessage()); receiver.txtInteractiveMessages.setText(Localization.get("bulk.form.error", new String[]{e.getMessage()})); receiver.transplantStyle(txtInteractiveMessages, R.layout.template_text_notification_problem); } }; mSendTask.connect(CommCareFormDumpActivity.this); mSendTask.execute(); } }); btnDumpForms.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Logger.log(AndroidLogger.TYPE_FORM_DUMP, "Dump task found " + formsOnSD + " forms on the SD card."); if (formsOnPhone == 0) { txtInteractiveMessages.setText(Localization.get("bulk.form.no.unsynced.dump")); transplantStyle(txtInteractiveMessages, R.layout.template_text_notification_problem); return; } DumpTask mDumpTask = new DumpTask(getApplicationContext()) { @Override protected void deliverResult(CommCareFormDumpActivity receiver, Boolean result) { if (result == Boolean.TRUE) { Intent i = new Intent(getIntent()); i.putExtra(AdvancedActionsActivity.KEY_NUMBER_DUMPED, formsOnPhone); receiver.setResult(BULK_DUMP_ID, i); Logger.log(AndroidLogger.TYPE_FORM_DUMP, "Successfully dumped " + formsOnPhone + " forms."); receiver.finish(); } else { //assume that we've already set the error message, but make it look scary receiver.transplantStyle(txtInteractiveMessages, R.layout.template_text_notification_problem); } } @Override protected void deliverUpdate(CommCareFormDumpActivity receiver, String... update) { receiver.updateProgress(update[0], BULK_DUMP_ID); receiver.txtInteractiveMessages.setText(update[0]); } @Override protected void deliverError(CommCareFormDumpActivity receiver, Exception e) { Logger.log(AndroidLogger.TYPE_FORM_DUMP, "Dump failed with exception: " + e.getMessage()); receiver.txtInteractiveMessages.setText(Localization.get("bulk.form.error", new String[]{e.getMessage()})); receiver.transplantStyle(txtInteractiveMessages, R.layout.template_text_notification_problem); } }; mDumpTask.connect(CommCareFormDumpActivity.this); mDumpTask.execute(); } }); if (!acknowledgedRisk) { showWarningMessage(); } } @Override protected void onSaveInstanceState(Bundle outState) { outState.putString(DUMP_FORMS_ERROR, txtInteractiveMessages.getText().toString()); super.onSaveInstanceState(outState); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); txtInteractiveMessages.setText(savedInstanceState.getString(DUMP_FORMS_ERROR)); transplantStyle(txtInteractiveMessages, R.layout.template_text_notification_problem); } private void showWarningMessage() { StandardAlertDialog d = new StandardAlertDialog(this, Localization.get("bulk.form.alert.title"), Localization.get("bulk.form.warning")); DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { dialog.dismiss(); if (id == AlertDialog.BUTTON_POSITIVE) { acknowledgedRisk = true; dismissAlertDialog(); } else { exitDump(); } } }; d.setPositiveButton("OK", listener); d.setNegativeButton("NO", listener); showAlertDialog(d); } private void updateCounters() { Vector<Integer> ids = getUnsyncedForms(); File[] files = getDumpFiles(); formsOnPhone = ids.size(); formsOnSD = files.length; setDisplayText(); } private void setDisplayText() { btnDumpForms.setText(this.localize("bulk.form.dump.2", new String[]{"" + formsOnPhone})); btnSubmitForms.setText(this.localize("bulk.form.submit.2", new String[]{"" + formsOnSD})); txtDisplayPrompt.setText(this.localize("bulk.form.prompt", new String[]{"" + formsOnPhone, "" + formsOnSD})); } private String getFolderName() { SharedPreferences settings = CommCareApplication.instance().getCurrentApp().getAppPreferences(); return settings.getString(CommCarePreferences.DUMP_FOLDER_PATH, Localization.get("bulk.form.foldername")); } private File getFolderPath() { String fileRoot = FileUtil.getDumpDirectory(this); if (fileRoot == null) { return null; } String folderName = getFolderName(); File dumpDirectory = new File(fileRoot + "/" + folderName); Logger.log(AndroidLogger.TYPE_FORM_DUMP, "Got folder path " + dumpDirectory); return dumpDirectory; } private File[] getDumpFiles() { File dumpDirectory = getFolderPath(); if (dumpDirectory == null || !dumpDirectory.isDirectory()) { return new File[]{}; } File[] files = dumpDirectory.listFiles(); Logger.log(AndroidLogger.TYPE_FORM_DUMP, "Found " + files.length + " dump files."); return files; } private Vector<Integer> getUnsyncedForms() { SqlStorage<FormRecord> storage = CommCareApplication.instance().getUserStorage(FormRecord.class); Vector<Integer> ids = StorageUtils.getUnsentOrUnprocessedFormIdsForCurrentApp(storage); Logger.log(AndroidLogger.TYPE_FORM_DUMP, "Found " + ids.size() + " unsynced forms."); return ids; } private void exitDump() { finish(); } @Override public void taskCancelled() { txtInteractiveMessages.setText(Localization.get("bulk.form.cancel")); this.transplantStyle(txtInteractiveMessages, R.layout.template_text_notification_problem); } /* Implementation of generateProgressDialog() for DialogController -- other methods * handled entirely in CommCareActivity */ @Override public CustomProgressDialog generateProgressDialog(int taskId) { String title, message; if (taskId == DumpTask.BULK_DUMP_ID) { title = Localization.get("bulk.dump.dialog.title"); message = Localization.get("bulk.dump.dialog.progress", new String[]{"0"}); } else if (taskId == SendTask.BULK_SEND_ID) { title = Localization.get("bulk.send.dialog.title"); message = Localization.get("bulk.send.dialog.progress", new String[]{"0"}); } else { Log.w(TAG, "taskId passed to generateProgressDialog does not match " + "any valid possibilities in CommCareFormDumpActivity"); return null; } return CustomProgressDialog.newInstance(title, message, taskId); } }