com.pacoapp.paco.ui.FeedbackActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.pacoapp.paco.ui.FeedbackActivity.java

Source

/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* 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.pacoapp.paco.ui;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.ConsoleMessage;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.LinearLayout;

import com.google.common.base.Strings;
import com.pacoapp.paco.PacoConstants;
import com.pacoapp.paco.R;
import com.pacoapp.paco.js.bridge.Environment;
import com.pacoapp.paco.js.bridge.JavascriptEmail;
import com.pacoapp.paco.js.bridge.JavascriptEventLoader;
import com.pacoapp.paco.js.bridge.JavascriptExperimentLoader;
import com.pacoapp.paco.js.bridge.JavascriptSensorManager;
import com.pacoapp.paco.js.bridge.JavascriptStringResources;
import com.pacoapp.paco.model.Event;
import com.pacoapp.paco.model.Experiment;
import com.pacoapp.paco.model.ExperimentProviderUtil;
import com.pacoapp.paco.model.Output;
import com.pacoapp.paco.shared.model2.ExperimentDAO;
import com.pacoapp.paco.shared.model2.ExperimentGroup;
import com.pacoapp.paco.shared.model2.Input2;
import com.pacoapp.paco.shared.model2.JsonConverter;
import com.pacoapp.paco.shared.util.ExperimentHelper;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.joda.time.DateTime;
import org.json.JSONArray;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class FeedbackActivity extends ActionBarActivity {

    private static final String TEMP_URL = null;
    ExperimentProviderUtil experimentProviderUtil;
    Experiment experiment;
    private WebView webView;
    private Button rawDataButton;
    boolean showDialog = true;
    private Environment env;
    private ExperimentGroup experimentGroup;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActionBar actionBar = getSupportActionBar();
        actionBar.setDisplayUseLogoEnabled(true);
        actionBar.setDisplayShowHomeEnabled(true);
        actionBar.setDisplayHomeAsUpEnabled(true);
        actionBar.setDisplayShowTitleEnabled(false);

        experimentProviderUtil = new ExperimentProviderUtil(this);
        loadExperimentInfoFromIntent();

        if (experiment == null || experimentGroup == null) {
            displayNoExperimentMessage();
        } else {
            setContentView(R.layout.feedback);

            // TODO revamp this to deal with null experimentGroup (do we give a list of groups? the exploredata button in runningexperiments needs this)

            rawDataButton = (Button) findViewById(R.id.rawDataButton);
            rawDataButton.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    Intent rawDataIntent = new Intent(FeedbackActivity.this, RawDataActivity.class);
                    rawDataIntent.putExtras(getIntent().getExtras());
                    startActivity(rawDataIntent);
                }
            });
            webView = (WebView) findViewById(R.id.feedbackText);
            webView.getSettings().setJavaScriptEnabled(true);

            final com.pacoapp.paco.shared.model2.Feedback feedback = experimentGroup.getFeedback();

            injectObjectsIntoJavascriptEnvironment(feedback);

            setWebChromeClientThatHandlesAlertsAsDialogs();

            WebViewClient webViewClient = createWebViewClientThatHandlesFileLinksForCharts(feedback);
            webView.setWebViewClient(webViewClient);

            if (experimentGroup.getFeedback().getType() != null && experimentGroup.getFeedback().getType()
                    .equals(com.pacoapp.paco.shared.model2.Feedback.FEEDBACK_TYPE_RETROSPECTIVE)) {
                // TODO get rid of this and just use the customFeedback view
                loadRetrospectiveFeedbackIntoWebView();
            } else {
                loadCustomFeedbackIntoWebView();
            }
            if (savedInstanceState != null) {
                String savedUrl = savedInstanceState.getString("url");
                if (!Strings.isNullOrEmpty(savedUrl)) {
                    webView.loadUrl(savedUrl);
                }
                showDialog = savedInstanceState.getBoolean("showDialog", false);

            }
        }

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == android.R.id.home) {
            finish();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private void injectObjectsIntoJavascriptEnvironment(final com.pacoapp.paco.shared.model2.Feedback feedback) {
        final Map<String, String> map = new HashMap<String, String>();
        map.put("experimentGroupName", experimentGroup.getName());
        map.put("title", experiment.getExperimentDAO().getTitle());
        map.put("test", "false");
        map.put("additions", experimentGroup.getFeedback().getText());
        env = new Environment(map);
        webView.addJavascriptInterface(env, "env");

        webView.addJavascriptInterface(new JavascriptEmail(this), "email");
        webView.addJavascriptInterface(new JavascriptExperimentLoader(this, experimentProviderUtil,
                experiment.getExperimentDAO(), experiment, experimentGroup), "experimentLoader");

        JavascriptEventLoader javascriptEventLoader = new JavascriptEventLoader(experimentProviderUtil, experiment,
                experiment.getExperimentDAO(), experimentGroup);
        webView.addJavascriptInterface(javascriptEventLoader, "db");
        webView.addJavascriptInterface(new JavascriptSensorManager(getApplicationContext()), "sensors");
        webView.addJavascriptInterface(new JavascriptStringResources(getApplicationContext()), "strings");

    }

    private void loadRetrospectiveFeedbackIntoWebView() {
        webView.loadUrl("file:///android_asset/retrospective_feedback.html");
    }

    private void loadCustomFeedbackIntoWebView() {
        webView.loadUrl("file:///android_asset/skeleton.html");
    }

    private WebViewClient createWebViewClientThatHandlesFileLinksForCharts(
            final com.pacoapp.paco.shared.model2.Feedback feedback) {
        WebViewClient webViewClient = new WebViewClient() {

            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                Uri uri = Uri.parse(url);
                if (uri.getScheme().startsWith("http")) {
                    return true; // throw away http requests - we don't want 3rd party javascript sending url requests due to security issues.
                }

                String inputIdStr = uri.getQueryParameter("inputId");
                if (inputIdStr == null) {
                    return true;
                }

                JSONArray results = new JSONArray();
                experimentProviderUtil.loadEventsForExperiment(experiment);
                for (Event event : experiment.getEvents()) {
                    JSONArray eventJson = new JSONArray();
                    DateTime responseTime = event.getResponseTime();
                    if (responseTime == null) {
                        continue; // missed signal;
                    }
                    eventJson.put(responseTime.getMillis());

                    // in this case we are looking for one input from the responses that we are charting.
                    for (Output response : event.getResponses()) {
                        if (response.getName().equals(inputIdStr)) {
                            Input2 inputById = ExperimentHelper.getInputWithName(experiment.getExperimentDAO(),
                                    inputIdStr, null);
                            if (inputById.isNumeric()) {
                                eventJson.put(response.getDisplayOfAnswer(inputById));
                                results.put(eventJson);
                                continue;
                            }
                        }
                    }

                }
                env.put("data", results.toString());
                env.put("inputId", inputIdStr);

                view.loadUrl(stripQuery(url));
                return true;
            }

        };
        return webViewClient;
    }

    public static String stripQuery(String url) {
        String urlWithoutQuery = url;
        int indexOfQuery = url.indexOf('?');
        if (indexOfQuery != -1) {
            urlWithoutQuery = urlWithoutQuery.substring(0, indexOfQuery);
        }
        return urlWithoutQuery;
    }

    private void setWebChromeClientThatHandlesAlertsAsDialogs() {
        webView.setWebChromeClient(new WebChromeClient() {
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {

                new AlertDialog.Builder(view.getContext()).setMessage(message).setCancelable(true)
                        .setPositiveButton(R.string.ok, new Dialog.OnClickListener() {

                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                            }

                        }).create().show();
                result.confirm();
                return true;
            }

            public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
                if (url.contains("file:///android_asset/map.html")) {
                    if (showDialog == false) {
                        result.confirm();
                        return true;
                    } else {
                        new AlertDialog.Builder(view.getContext()).setMessage(message).setCancelable(true)
                                .setPositiveButton(R.string.ok, new Dialog.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int which) {
                                        showDialog = false;
                                        dialog.dismiss();
                                        result.confirm();
                                    }
                                }).setNegativeButton(R.string.cancel_button, new Dialog.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int which) {
                                        dialog.dismiss();
                                        result.cancel();
                                    }
                                }).create().show();
                        return true;
                    }
                }
                return super.onJsConfirm(view, url, message, result);
            }

            @Override
            public void onConsoleMessage(String message, int lineNumber, String sourceID) {
                Log.d(PacoConstants.TAG, message + " -- From line " + lineNumber + " of " + sourceID);
            }

            @Override
            public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
                Log.d(PacoConstants.TAG, "*" + consoleMessage.message() + " -- From line "
                        + consoleMessage.lineNumber() + " of " + consoleMessage.sourceId());
                return true;
            }

        });
    }

    public static String convertExperimentResultsToJsonString(
            final com.pacoapp.paco.shared.model2.Feedback feedback, final Experiment experiment) {
        List<Event> events = experiment.getEvents();
        return convertEventsToJsonString(events);
    }

    public static String convertLastEventToJsonString(List<Event> events) {
        if (events.isEmpty()) {
            return "[]";
        }
        return convertEventsToJsonString(events.subList(0, 1));
    }

    public static String convertEventsToJsonString(List<Event> events) {
        ObjectMapper mapper = JsonConverter.getObjectMapper();

        String eventJson = null;
        try {
            eventJson = mapper.writeValueAsString(events);
        } catch (JsonGenerationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (JsonMappingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return eventJson;

        // TODO use jackson instead. But preserve these synthesized values for backward compatibility.
        //    final JSONArray experimentData = new JSONArray();
        //    for (Event event : events) {
        //      try {
        //        JSONObject eventObject = new JSONObject();
        //        boolean missed = event.getResponseTime() == null;
        //        eventObject.put("isMissedSignal", missed);
        //        if (!missed) {
        //          eventObject.put("responseTime", event.getResponseTime().getMillis());
        //        }
        //
        //        boolean selfReport = event.getScheduledTime() == null;
        //        eventObject.put("isSelfReport", selfReport);
        //        if (!selfReport) {
        //          eventObject.put("scheduleTime", event.getScheduledTime().getMillis());
        //        }
        //
        //        JSONArray responses = new JSONArray();
        //        for (Output response : event.getResponses()) {
        //          JSONObject responseJson = new JSONObject();
        //          Input2 input = experiment.getInputByName(response.getName());
        //          if (input == null) {
        //            // just create the event based on all of the values in the datum
        //            responseJson.put("name", response.getName());
        //            responseJson.put("isMultiselect", false);
        //            responseJson.put("prompt", feedback.getTextOfInputForOutput(experiment.getExperimentDAO(), response));
        //            responseJson.put("answer", response.getAnswer());
        //            // deprecate answerOrder for answerRaw
        //            responseJson.put("answerOrder", response.getAnswer());
        //            responseJson.put("answerRaw", response.getAnswer());
        //            responses.put(responseJson);
        //          } else {
        //            responseJson.put("name", input.getName());
        //            responseJson.put("responseType", input.getResponseType());
        //            responseJson.put("isMultiselect", input.getMultiselect());
        //            responseJson.put("prompt", feedback.getTextOfInputForOutput(experiment, response));
        //            responseJson.put("answer", response.getDisplayOfAnswer(input));
        //            // deprecate answerOrder for answerRaw
        //            responseJson.put("answerOrder", response.getAnswer());
        //            responseJson.put("answerRaw", response.getAnswer());
        //            responses.put(responseJson);
        //          }
        //        }
        //
        //        eventObject.put("responses", responses);
        //        if (responses.length() > 0) {
        //          experimentData.put(eventObject);
        //        }
        //      } catch (JSONException jse) {
        //        // skip this event and do the next event.
        //      }
        //    }
        //    String experimentDataAsJson = experimentData.toString();
        //    return experimentDataAsJson;
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
            webView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    private void displayNoExperimentMessage() {
        LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        LinearLayout mainLayout = (LinearLayout) inflater.inflate(R.layout.could_not_load_experiment, null);
        setContentView(mainLayout);

    }

    @Override
    protected void onStop() {
        super.onStop();
        //finish();
    }

    private void loadExperimentInfoFromIntent() {
        Bundle extras = getIntent().getExtras();
        if (extras == null) {
            return;
        }
        if (extras.containsKey(Experiment.EXPERIMENT_SERVER_ID_EXTRA_KEY)) {
            long experimentServerId = extras.getLong(Experiment.EXPERIMENT_SERVER_ID_EXTRA_KEY);
            experiment = experimentProviderUtil.getExperimentByServerId(experimentServerId);
            if (experiment != null && extras.containsKey(Experiment.EXPERIMENT_GROUP_NAME_EXTRA_KEY)) {
                String experimentGroupName = extras.getString(Experiment.EXPERIMENT_GROUP_NAME_EXTRA_KEY);
                experimentGroup = experiment.getExperimentDAO().getGroupByName(experimentGroupName);
            }
        }
    }

    String getTextOfInputForOutput(ExperimentDAO experiment, Output output) {
        for (Input2 input : ExperimentHelper.getInputs(experiment)) {
            if (input.getName().equals(output.getName())) {
                if (!input.isInvisible()) {
                    return input.getText();
                } else {
                    return input.getResponseType();
                }
            }
        }
        return output.getName();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        if (webView != null) {
            outState.putString("url", webView.getUrl());
        }
        outState.putBoolean("showDialog", showDialog);
    }

    // TODO resolve whether this should be here or in the onCreate method.
    //  @Override
    //  protected void onRestoreInstanceState(Bundle savedInstanceState) {
    //    super.onRestoreInstanceState(savedInstanceState);
    //    String url = savedInstanceState.getString("url");
    //    if (url != null) {
    //      if (webView != null) {
    //        webView.loadUrl(url);
    //      }
    //    }
    //    showDialog = savedInstanceState.getBoolean("showDialog", false);
    //  }
    //

}