package net.hockeyapp.android.tasks; import android.app.ProgressDialog; import android.content.Context; import android.content.SharedPreferences; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.Message; import net.hockeyapp.android.Constants; import net.hockeyapp.android.R; import net.hockeyapp.android.utils.HockeyLog; import net.hockeyapp.android.utils.HttpURLConnectionBuilder; import net.hockeyapp.android.utils.Util; import java.io.File; import java.io.IOException; import java.net.HttpURLConnection; import java.util.HashMap; import java.util.List; import java.util.Map; /** * <h3>Description</h3> * * Internal helper class. Sends feedback to server. * **/ public class SendFeedbackTask extends ConnectionTask<Void, Void, HashMap<String, String>> { public static final String BUNDLE_FEEDBACK_RESPONSE = "feedback_response"; public static final String BUNDLE_FEEDBACK_STATUS = "feedback_status"; public static final String BUNDLE_REQUEST_TYPE = "request_type"; private static final String TAG = "SendFeedbackTask"; private static final String FILE_TAG = "HockeyApp"; private Context mContext; private Handler mHandler; private String mUrlString; private String mName; private String mEmail; private String mSubject; private String mText; private List<Uri> mAttachmentUris; private String mToken; private boolean mIsFetchMessages; private ProgressDialog mProgressDialog; private boolean mShowProgressDialog; private int mLastMessageId; /** * Send feedback {@link AsyncTask}. * If the class is intended to send a simple feedback message, the a POST is made with the * specific data * If the class is intended to fetch the messages by providing a token, a GET is made * * @param context {@link Context} object * @param urlString URL for sending feedback/fetching messages * @param name Name of the feedback sender * @param email Email of the feedback sender * @param subject Message subject * @param text The message * @param attachmentUris List of all attached files * @param token Token received after sending the first feedback. This should be * stored in {@link SharedPreferences} * @param handler Handler object to send data back to the activity * @param isFetchMessages If true, the {@link AsyncTask} will perform a GET, fetching the * messages. * If false, the {@link AsyncTask} will perform a POST, sending the * feedback message */ public SendFeedbackTask(Context context, String urlString, String name, String email, String subject, String text, List<Uri> attachmentUris, String token, Handler handler, boolean isFetchMessages) { this.mContext = context; this.mUrlString = urlString; this.mName = name; this.mEmail = email; this.mSubject = subject; this.mText = text; this.mAttachmentUris = attachmentUris; this.mToken = token; this.mHandler = handler; this.mIsFetchMessages = isFetchMessages; this.mShowProgressDialog = true; this.mLastMessageId = -1; if (context != null) { Constants.loadFromContext(context); } } public void setShowProgressDialog(boolean showProgressDialog) { this.mShowProgressDialog = showProgressDialog; } public void setLastMessageId(int lastMessageId) { this.mLastMessageId = lastMessageId; } public void attach(Context context) { this.mContext = context; } public void detach() { mContext = null; mProgressDialog = null; } @Override protected void onPreExecute() { String loadingMessage = mContext.getString(R.string.hockeyapp_feedback_sending_feedback_text); if (mIsFetchMessages) { loadingMessage = mContext.getString(R.string.hockeyapp_feedback_fetching_feedback_text); } if ((mProgressDialog == null || !mProgressDialog.isShowing()) && mShowProgressDialog) { mProgressDialog = ProgressDialog.show(mContext, "", loadingMessage, true, false); } } @Override protected HashMap<String, String> doInBackground(Void... args) { if (mIsFetchMessages && mToken != null) { /** If we are fetching messages then do a GET */ return doGet(); } else { /** * If we are sending a feedback do POST, and if we are sending a feedback * to an existing discussion do PUT */ if (!mIsFetchMessages) { if (mAttachmentUris.isEmpty()) { return doPostPut(); } else { HashMap<String, String> result = doPostPutWithAttachments(); if (result != null) { clearTemporaryFolder(result); } return result; } } else { return null; } } } private void clearTemporaryFolder(HashMap<String, String> result) { String status = result.get("status"); if ((status != null) && (status.startsWith("2")) && (mContext != null)) { File folder = new File(mContext.getCacheDir(), FILE_TAG); if ((folder != null) && folder.exists()) { for (File file : folder.listFiles()) { if (file != null) { Boolean success = file.delete(); if (!success) { HockeyLog.debug(TAG, "Error deleting file from temporary folder"); } } } } } } @Override protected void onPostExecute(HashMap<String, String> result) { if (mProgressDialog != null) { try { mProgressDialog.dismiss(); } catch (Exception e) { e.printStackTrace(); } } /** If the Handler object is not NULL, send a message to the Activity with the result */ if (mHandler != null) { Message msg = new Message(); Bundle bundle = new Bundle(); if (result != null) { bundle.putString(BUNDLE_REQUEST_TYPE, result.get("type")); bundle.putString(BUNDLE_FEEDBACK_RESPONSE, result.get("response")); bundle.putString(BUNDLE_FEEDBACK_STATUS, result.get("status")); } else { bundle.putString(BUNDLE_REQUEST_TYPE, "unknown"); } msg.setData(bundle); mHandler.sendMessage(msg); } } /** * POST/PUT * * @return */ private HashMap<String, String> doPostPut() { HashMap<String, String> result = new HashMap<String, String>(); result.put("type", "send"); HttpURLConnection urlConnection = null; try { Map<String, String> parameters = new HashMap<String, String>(); parameters.put("name", mName); parameters.put("email", mEmail); parameters.put("subject", mSubject); parameters.put("text", mText); parameters.put("bundle_identifier", Constants.APP_PACKAGE); parameters.put("bundle_short_version", Constants.APP_VERSION_NAME); parameters.put("bundle_version", Constants.APP_VERSION); parameters.put("os_version", Constants.ANDROID_VERSION); parameters.put("oem", Constants.PHONE_MANUFACTURER); parameters.put("model", Constants.PHONE_MODEL); parameters.put("sdk_version", Constants.SDK_VERSION); if (mToken != null) { mUrlString += mToken + "/"; } urlConnection = new HttpURLConnectionBuilder(mUrlString) .setRequestMethod(mToken != null ? "PUT" : "POST") .writeFormFields(parameters) .build(); urlConnection.connect(); result.put("status", String.valueOf(urlConnection.getResponseCode())); result.put("response", getStringFromConnection(urlConnection)); } catch (IOException e) { e.printStackTrace(); } finally { if (urlConnection != null) { urlConnection.disconnect(); } } return result; } /** * POST/PUT with attachments * * @return */ private HashMap<String, String> doPostPutWithAttachments() { HashMap<String, String> result = new HashMap<String, String>(); result.put("type", "send"); HttpURLConnection urlConnection = null; try { Map<String, String> parameters = new HashMap<String, String>(); parameters.put("name", mName); parameters.put("email", mEmail); parameters.put("subject", mSubject); parameters.put("text", mText); parameters.put("bundle_identifier", Constants.APP_PACKAGE); parameters.put("bundle_short_version", Constants.APP_VERSION_NAME); parameters.put("bundle_version", Constants.APP_VERSION); parameters.put("os_version", Constants.ANDROID_VERSION); parameters.put("oem", Constants.PHONE_MANUFACTURER); parameters.put("model", Constants.PHONE_MODEL); parameters.put("sdk_version", Constants.SDK_VERSION); if (mToken != null) { mUrlString += mToken + "/"; } urlConnection = new HttpURLConnectionBuilder(mUrlString) .setRequestMethod(mToken != null ? "PUT" : "POST") .writeMultipartData(parameters, mContext, mAttachmentUris) .build(); urlConnection.connect(); result.put("status", String.valueOf(urlConnection.getResponseCode())); result.put("response", getStringFromConnection(urlConnection)); } catch (IOException e) { e.printStackTrace(); } finally { if (urlConnection != null) { urlConnection.disconnect(); } } return result; } /** * GET * * @return */ private HashMap<String, String> doGet() { StringBuilder sb = new StringBuilder(); sb.append(mUrlString + Util.encodeParam(mToken)); if (mLastMessageId != -1) { sb.append("?last_message_id=" + mLastMessageId); } HashMap<String, String> result = new HashMap<String, String>(); HttpURLConnection urlConnection = null; try { urlConnection = new HttpURLConnectionBuilder(sb.toString()) .build(); result.put("type", "fetch"); urlConnection.connect(); result.put("status", String.valueOf(urlConnection.getResponseCode())); result.put("response", getStringFromConnection(urlConnection)); } catch (IOException e) { e.printStackTrace(); } finally { if (urlConnection != null) { urlConnection.disconnect(); } } return result; } }