/* * 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 com.radicaldynamic.groupinform.activities; import com.radicaldynamic.groupinform.R; import org.odk.collect.android.listeners.InstanceUploaderListener; import org.odk.collect.android.preferences.PreferencesActivity; import org.odk.collect.android.utilities.WebUtils; import com.radicaldynamic.groupinform.activities.FormEntryActivity; import com.radicaldynamic.groupinform.application.Collect; import com.radicaldynamic.groupinform.documents.FormDefinition; import com.radicaldynamic.groupinform.repositories.FormDefinitionRepo; import com.radicaldynamic.groupinform.tasks.InstanceUploaderTask; import com.radicaldynamic.groupinform.utilities.DocumentUtils; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.EditText; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Set; /** * Activity to upload completed forms. * * @author Carl Hartung (carlhartung@gmail.com) */ public class InstanceUploaderActivity extends Activity implements InstanceUploaderListener { private final static String t = "InstanceUploaderActivity"; private final static int PROGRESS_DIALOG = 1; private final static int AUTH_DIALOG = 2; private ProgressDialog mProgressDialog; private AlertDialog mAlertDialog; private String mAlertMsg; private String ALERT_MSG = "alertmsg"; private String ALERT_SHOWING = "alertshowing"; private static final String TO_SEND = "tosend"; private boolean mAlertShowing; private InstanceUploaderTask mInstanceUploaderTask; // maintain a list of what we've yet to send, in case we're interrupted by auth requests // BEGIN custom // private ArrayList<Long> mInstancesToSend; private ArrayList<String> mInstancesToSend; private Bundle mUploadBundle; // END custom // maintain a list of what we've sent, in case we're interrupted by auth requests private HashMap<String, String> mUploadedInstances; private String mUrl; private final static String AUTH_URI = "auth"; @SuppressWarnings("unchecked") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mAlertMsg = getString(R.string.please_wait); mUploadedInstances = new HashMap<String, String>(); setTitle(getString(R.string.app_name) + " > " + getString(R.string.send_data)); // get instances to upload Intent intent = getIntent(); // BEGIN custom // long[] selectedInstanceIDs = intent.getLongArrayExtra(FormEntryActivity.KEY_INSTANCES); // if (selectedInstanceIDs.length == 0) { // // If we get nothing, toast and quit // Toast.makeText(this, R.string.noselect_error, Toast.LENGTH_LONG); // finish(); // return; // } if (intent.hasExtra(FormEntryActivity.KEY_INSTANCES)) { mUploadBundle = intent.getBundleExtra(FormEntryActivity.KEY_INSTANCES); mInstancesToSend = new ArrayList<String>(); Set<String> formIds = mUploadBundle.keySet(); Iterator<String> formIterator = formIds.iterator(); while (formIterator.hasNext()) { String formId = formIterator.next(); mInstancesToSend.addAll(mUploadBundle.getStringArrayList(formId)); } } // END custom if (savedInstanceState != null) { if (savedInstanceState.containsKey(ALERT_MSG)) { mAlertMsg = savedInstanceState.getString(ALERT_MSG); } if (savedInstanceState.containsKey(ALERT_SHOWING)) { mAlertShowing = savedInstanceState.getBoolean(ALERT_SHOWING, false); } // BEGIN custom if (savedInstanceState.containsKey(FormEntryActivity.KEY_INSTANCES)) { mUploadBundle = savedInstanceState.getBundle(FormEntryActivity.KEY_INSTANCES); } // END custom } if (savedInstanceState != null && !savedInstanceState.containsKey(TO_SEND)) { // BEGIN custom // mInstancesToSend = (ArrayList<Long>) savedInstanceState.getSerializable(TO_SEND); mInstancesToSend = (ArrayList<String>) savedInstanceState.getSerializable(TO_SEND); // END custom } else { // BEGIN custom // mInstancesToSend = new ArrayList<Long>(); // for (int i = 0; i < selectedInstanceIDs.length; i++) { // mInstancesToSend.add(new Long(selectedInstanceIDs[i])); // } // END custom } // get the task if we've changed orientations. If it's null it's a new upload. mInstanceUploaderTask = (InstanceUploaderTask) getLastNonConfigurationInstance(); if (mInstanceUploaderTask == null) { // setup dialog and upload task showDialog(PROGRESS_DIALOG); SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); mInstanceUploaderTask = new InstanceUploaderTask(); // register this activity with the new uploader task mInstanceUploaderTask.setUploaderListener(InstanceUploaderActivity.this); // BEGIN custom // Long[] toSendArray = new Long[mInstancesToSend.size()]; // mInstancesToSend.toArray(toSendArray); // mInstanceUploaderTask.execute(toSendArray); String auth = settings.getString(PreferencesActivity.KEY_AUTH, ""); mInstanceUploaderTask.setAuth(auth); String [] instances = mInstancesToSend.toArray(new String[mInstancesToSend.size()]); mInstanceUploaderTask.execute(instances); // END custom } } @Override public void uploadingComplete(HashMap<String, String> result) { try { dismissDialog(PROGRESS_DIALOG); } catch (Exception e) { // tried to close a dialog not open. don't care. } // BEGIN custom // StringBuilder selection = new StringBuilder(); // Set<String> keys = result.keySet(); // Iterator<String> it = keys.iterator(); // // String[] selectionArgs = new String[keys.size()]; // int i = 0; // while (it.hasNext()) { // String id = it.next(); // selection.append(InstanceColumns._ID + "=?"); // selectionArgs[i++] = id; // if (i != keys.size()) { // selection.append(" or "); // } // } // // // Cursor results = // managedQuery(InstanceColumns.CONTENT_URI, null, selection.toString(), selectionArgs, // null); // StringBuilder message = new StringBuilder(); // if (results.getCount() > 0) { // results.moveToPosition(-1); // while (results.moveToNext()) { // String name = // results.getString(results.getColumnIndex(InstanceColumns.DISPLAY_NAME)); // String id = results.getString(results.getColumnIndex(InstanceColumns._ID)); // message.append(name + " - " + result.get(id) + "\n\n"); // } // } else { // message.append(getString(R.string.no_forms_uploaded)); // } // // createAlertDialog(message.toString().trim); try { FormDefinitionRepo repo = new FormDefinitionRepo(Collect.getInstance().getDbService().getDb()); ArrayList<FormDefinition> definitions = (ArrayList<FormDefinition>) repo.getAllActiveByKeys(new ArrayList<Object>(mUploadBundle.keySet())); DocumentUtils.sortDefinitionsByName(definitions); StringBuilder b = new StringBuilder(); Iterator<FormDefinition> definitionIterator = definitions.iterator(); while (definitionIterator.hasNext()) { StringBuilder errors = new StringBuilder(); FormDefinition d = definitionIterator.next(); b.append(d.getName() + ": sent "); int totalUploads = 0; int successfulUploads = 0; Iterator<String> instanceIterator = mUploadBundle.getStringArrayList(d.getId()).iterator(); while (instanceIterator.hasNext()) { String i = instanceIterator.next(); totalUploads++; if (result.get(i).equals(Collect.getInstance().getString(R.string.success).toString())) successfulUploads++; else errors.append(result.get(i) + "\n"); } b.append(successfulUploads + "/" + totalUploads + "\n"); if (errors.length() > 0) { b.append("Errors: "); b.append(errors.toString()); } if (definitionIterator.hasNext()) b.append("\n\n"); } createAlertDialog(b.toString().trim()); } catch (Exception e) { createAlertDialog("Error attempting to summarize upload results:\n" + e.toString()); if (Collect.Log.ERROR) Log.e(Collect.LOGTAG, t + ": unable to summarize upload results"); e.printStackTrace(); } // END custom } @Override public void progressUpdate(int progress, int total) { mAlertMsg = getString(R.string.sending_items, progress, total); mProgressDialog.setMessage(mAlertMsg); } @Override protected Dialog onCreateDialog(int id) { switch (id) { case PROGRESS_DIALOG: mProgressDialog = new ProgressDialog(this); DialogInterface.OnClickListener loadingButtonListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); mInstanceUploaderTask.cancel(true); mInstanceUploaderTask.setUploaderListener(null); finish(); } }; mProgressDialog.setTitle(getString(R.string.uploading_data)); mProgressDialog.setMessage(mAlertMsg); mProgressDialog.setIndeterminate(true); mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); mProgressDialog.setCancelable(false); mProgressDialog.setButton(getString(R.string.cancel), loadingButtonListener); return mProgressDialog; case AUTH_DIALOG: AlertDialog.Builder b = new AlertDialog.Builder(this); LayoutInflater factory = LayoutInflater.from(this); final View dialogView = factory.inflate(R.layout.server_auth_dialog, null); // Get the server, username, and password from the settings SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); String server = mUrl; if (server == null) { // if the bundle is null, we're looking for a formlist server = settings.getString(PreferencesActivity.KEY_SERVER_URL, getString(R.string.default_server_url)) + settings.getString(PreferencesActivity.KEY_FORMLIST_URL, "/formList"); } final String url = server; Log.i(t, "Trying connecting to: " + url); EditText username = (EditText) dialogView.findViewById(R.id.username_edit); String storedUsername = settings.getString(PreferencesActivity.KEY_USERNAME, null); username.setText(storedUsername); EditText password = (EditText) dialogView.findViewById(R.id.password_edit); String storedPassword = settings.getString(PreferencesActivity.KEY_PASSWORD, null); password.setText(storedPassword); b.setTitle(getString(R.string.server_requires_auth)); b.setMessage(getString(R.string.server_auth_credentials, url)); b.setView(dialogView); b.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { EditText username = (EditText) dialogView.findViewById(R.id.username_edit); EditText password = (EditText) dialogView.findViewById(R.id.password_edit); URI u = URI.create(mUrl); WebUtils.addCredentials(username.getText().toString(), password.getText() .toString(), u.getHost()); mInstanceUploaderTask = new InstanceUploaderTask(); // register this activity with the new uploader task mInstanceUploaderTask.setUploaderListener(InstanceUploaderActivity.this); // BEGIN custom // Long[] toSendArray = new Long[mInstancesToSend.size()]; String[] toSendArray = new String[mInstancesToSend.size()]; // END custom mInstancesToSend.toArray(toSendArray); mInstanceUploaderTask.execute(toSendArray); showDialog(PROGRESS_DIALOG); } }); b.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }); b.setCancelable(false); return b.create(); } return null; } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); mUrl = savedInstanceState.getString(AUTH_URI); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString(ALERT_MSG, mAlertMsg); outState.putBoolean(ALERT_SHOWING, mAlertShowing); outState.putSerializable(TO_SEND, mInstancesToSend); outState.putString(AUTH_URI, mUrl); // BEGIN custom outState.putBundle(FormEntryActivity.KEY_INSTANCES, mUploadBundle); // END custom } @Override public Object onRetainNonConfigurationInstance() { return mInstanceUploaderTask; } @Override protected void onDestroy() { if (mInstanceUploaderTask != null) { mInstanceUploaderTask.setUploaderListener(null); } super.onDestroy(); } @Override protected void onPause() { super.onPause(); if (mAlertDialog != null && mAlertDialog.isShowing()) { mAlertDialog.dismiss(); } } @Override protected void onResume() { if (mInstanceUploaderTask != null) { mInstanceUploaderTask.setUploaderListener(this); } if (mAlertShowing) { createAlertDialog(mAlertMsg); } super.onResume(); } @Override public void authRequest(URI url, HashMap<String, String> doneSoFar) { if (mProgressDialog.isShowing()) { // should always be showing here mProgressDialog.dismiss(); } // add our list of completed uploads to "completed" // and remove them from our toSend list. if (doneSoFar != null) { Set<String> uploadedInstances = doneSoFar.keySet(); Iterator<String> itr = uploadedInstances.iterator(); while (itr.hasNext()) { Long removeMe = new Long(itr.next()); boolean removed = mInstancesToSend.remove(removeMe); if (removed) { Log.i(t, removeMe + " was already sent, removing from queue before restarting task"); } } mUploadedInstances.putAll(doneSoFar); } // Bundle b = new Bundle(); // b.putString(AUTH_URI, url.toString()); // showDialog(AUTH_DIALOG, b); mUrl = url.toString(); showDialog(AUTH_DIALOG); } private void createAlertDialog(String message) { mAlertDialog = new AlertDialog.Builder(this).create(); mAlertDialog.setTitle(getString(R.string.upload_results)); mAlertDialog.setMessage(message); DialogInterface.OnClickListener quitListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int i) { switch (i) { case DialogInterface.BUTTON1: // ok // always exit this activity since it has no interface mAlertShowing = false; finish(); break; } } }; mAlertDialog.setCancelable(false); mAlertDialog.setButton(getString(R.string.ok), quitListener); mAlertDialog.setIcon(android.R.drawable.ic_dialog_info); mAlertShowing = true; mAlertMsg = message; mAlertDialog.show(); } }