package org.commcare.activities;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import org.commcare.core.network.ModernHttpRequester;
import org.commcare.dalvik.R;
import org.commcare.interfaces.ConnectorWithHttpResponseProcessor;
import org.commcare.tasks.DataPullTask;
import org.commcare.tasks.SimpleHttpTask;
import org.commcare.tasks.templates.CommCareTaskConnector;
import org.commcare.views.ManagedUi;
import org.commcare.views.UiElement;
import org.commcare.views.dialogs.CustomProgressDialog;
import org.javarosa.core.services.locale.Localization;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
/**
* Perform post request to external server and trigger a sync upon success.
* Can be used to perform server transactions, to, for instance, claim a case
* and pull it down to the mobile device
*
* @author Phillip Mates (pmates@dimagi.com).
*/
@ManagedUi(R.layout.http_request_layout)
public class PostRequestActivity
extends SyncCapableCommCareActivity<PostRequestActivity>
implements ConnectorWithHttpResponseProcessor<PostRequestActivity> {
private static final String TAG = PostRequestActivity.class.getSimpleName();
private static final String TASK_LAUNCHED_KEY = "task-launched-key";
private static final String IN_ERROR_STATE_KEY = "in-error-state-key";
private static final String ERROR_MESSAGE_KEY = "error-message-key";
public static final String URL_KEY = "url-key";
public static final String PARAMS_KEY = "params-key";
@UiElement(value = R.id.request_button, locale = "post.request.button")
private Button retryButton;
@UiElement(value = R.id.error_message)
private TextView errorMessageBox;
private URL url;
private HashMap<String, String> params;
private String errorMessage;
private boolean hasTaskLaunched;
private boolean inErrorState;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loadStateFromSavedInstance(savedInstanceState);
loadStateFromIntent(getIntent());
setupUI();
if (!inErrorState) {
makePostRequest();
}
}
private void loadStateFromSavedInstance(Bundle savedInstanceState) {
if (savedInstanceState != null) {
hasTaskLaunched = savedInstanceState.getBoolean(TASK_LAUNCHED_KEY);
inErrorState = savedInstanceState.getBoolean(IN_ERROR_STATE_KEY);
errorMessage = savedInstanceState.getString(ERROR_MESSAGE_KEY);
}
}
private void loadStateFromIntent(Intent intent) {
if (intent.hasExtra(URL_KEY) && intent.hasExtra(PARAMS_KEY)) {
url = (URL)intent.getSerializableExtra(URL_KEY);
Object o = intent.getSerializableExtra(PARAMS_KEY);
params = (HashMap<String, String>)o;
} else {
enterErrorState(Localization.get("post.generic.error"));
}
}
private void setupUI() {
if (inErrorState) {
enterErrorState();
} else {
retryButton.setVisibility(View.GONE);
}
retryButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
retryPost();
}
});
}
private void performSync() {
formAndDataSyncer.syncDataForLoggedInUser(this, false, false);
}
private void makePostRequest() {
if (!hasTaskLaunched && !inErrorState) {
SimpleHttpTask postTask;
try {
postTask = new SimpleHttpTask(this, url, params, true, null);
} catch (ModernHttpRequester.PlainTextPasswordException e) {
enterErrorState(Localization.get("post.not.using.https", url.toString()));
return;
}
postTask.connect((CommCareTaskConnector)this);
postTask.executeParallel();
hasTaskLaunched = true;
}
}
private void enterErrorState() {
inErrorState = true;
errorMessageBox.setVisibility(View.VISIBLE);
errorMessageBox.setText(errorMessage);
retryButton.setVisibility(View.VISIBLE);
}
private void enterErrorState(String message) {
errorMessage = message;
enterErrorState();
}
private void retryPost() {
inErrorState = false;
errorMessage = "";
errorMessageBox.setVisibility(View.GONE);
hasTaskLaunched = false;
makePostRequest();
}
@Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putBoolean(TASK_LAUNCHED_KEY, hasTaskLaunched);
savedInstanceState.putBoolean(IN_ERROR_STATE_KEY, inErrorState);
savedInstanceState.putString(ERROR_MESSAGE_KEY, errorMessage);
}
@Override
protected void updateUiAfterDataPullOrSend(String message, boolean success) {
if (success) {
setResult(RESULT_OK);
finish();
} else {
enterErrorState(message);
}
}
@Override
public void processSuccess(int responseCode, InputStream responseData) {
performSync();
}
@Override
public void processRedirection(int responseCode) {
enterErrorState(Localization.get("post.redirection.error", responseCode + ""));
}
@Override
public void processClientError(int responseCode) {
String clientErrorMessage;
switch (responseCode) {
case 409:
clientErrorMessage =Localization.get("post.conflict.error");
break;
case 410:
clientErrorMessage =Localization.get("post.gone.error");
break;
default:
clientErrorMessage =Localization.get("post.client.error", responseCode + "");
break;
}
enterErrorState(clientErrorMessage);
}
@Override
public void processServerError(int responseCode) {
enterErrorState(Localization.get("post.server.error", responseCode + ""));
}
@Override
public void processOther(int responseCode) {
enterErrorState(Localization.get("post.unknown.response", responseCode + ""));
}
@Override
public void handleIOException(IOException exception) {
enterErrorState(Localization.get("post.io.error", exception.getMessage()));
}
@Override
public void onBackPressed() {
if (inErrorState) {
finish();
}
}
@Override
public CustomProgressDialog generateProgressDialog(int taskId) {
String title, message;
switch (taskId) {
case DataPullTask.DATA_PULL_TASK_ID:
title = Localization.get("sync.communicating.title");
message = Localization.get("sync.progress.purge");
break;
case SimpleHttpTask.SIMPLE_HTTP_TASK_ID:
title = Localization.get("post.dialog.title");
message = Localization.get("post.dialog.body");
break;
default:
Log.w(TAG, "taskId passed to generateProgressDialog does not match "
+ "any valid possibilities in activity");
return null;
}
return CustomProgressDialog.newInstance(title, message, taskId);
}
@Override
public boolean shouldShowSyncItemInActionBar() {
return false;
}
@Override
public boolean usesSubmissionProgressBar() {
return false;
}
}