/*
* 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();
}
}