package org.commcare.views.widgets; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.text.Spannable; import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; import org.commcare.activities.GeoPointActivity; import org.commcare.activities.GeoPointMapActivity; import org.commcare.activities.components.FormEntryConstants; import org.commcare.dalvik.R; import org.commcare.logic.PendingCalloutInterface; import org.commcare.utils.StringUtils; import org.javarosa.core.model.data.GeoPointData; import org.javarosa.core.model.data.IAnswerData; import org.javarosa.form.api.FormEntryPrompt; import java.text.DecimalFormat; /** * GeoPointWidget is the widget that allows the user to get GPS readings. * * @author Carl Hartung (carlhartung@gmail.com) * @author Yaw Anokwa (yanokwa@gmail.com) */ public class GeoPointWidget extends QuestionWidget { private final Button mGetLocationButton; private final Button mViewButton; private final TextView mStringAnswer; private final TextView mAnswerDisplay; private boolean mUseMaps; public static final String LOCATION = "gp"; private final PendingCalloutInterface pendingCalloutInterface; public GeoPointWidget(Context context, final FormEntryPrompt prompt, PendingCalloutInterface pic) { super(context, prompt); this.pendingCalloutInterface = pic; mUseMaps = false; String appearance = prompt.getAppearanceHint(); if ("maps".equalsIgnoreCase(appearance)) { try { // use google maps it exists on the device Class.forName("com.google.android.maps.MapActivity"); mUseMaps = true; } catch (ClassNotFoundException e) { mUseMaps = false; } } setOrientation(LinearLayout.VERTICAL); mStringAnswer = new TextView(getContext()); mAnswerDisplay = new TextView(getContext()); mAnswerDisplay.setTextSize(TypedValue.COMPLEX_UNIT_DIP, mAnswerFontSize); mAnswerDisplay.setGravity(Gravity.CENTER); Spannable locButtonText; boolean viewButtonEnabled; String s = prompt.getAnswerText(); if (s != null && !("".equals(s))) { setBinaryData(s); locButtonText = StringUtils.getStringSpannableRobust(getContext(), R.string.replace_location); viewButtonEnabled = true; } else { locButtonText = StringUtils.getStringSpannableRobust(getContext(), R.string.get_location); viewButtonEnabled = false; } mGetLocationButton = new Button(getContext()); WidgetUtils.setupButton(mGetLocationButton, locButtonText, mAnswerFontSize, !prompt.isReadOnly()); mGetLocationButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent i; if (mUseMaps) { i = new Intent(getContext(), GeoPointMapActivity.class); } else { i = new Intent(getContext(), GeoPointActivity.class); } ((Activity)getContext()).startActivityForResult(i, FormEntryConstants.LOCATION_CAPTURE); pendingCalloutInterface.setPendingCalloutFormIndex(prompt.getIndex()); } }); // setup 'view location' button mViewButton = new Button(getContext()); WidgetUtils.setupButton(mViewButton, StringUtils.getStringSpannableRobust(getContext(), R.string.show_location), mAnswerFontSize, viewButtonEnabled); // launch appropriate map viewer mViewButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String s = mStringAnswer.getText().toString(); String[] sa = s.split(" "); double gp[] = new double[4]; gp[0] = Double.valueOf(sa[0]); gp[1] = Double.valueOf(sa[1]); gp[2] = Double.valueOf(sa[2]); gp[3] = Double.valueOf(sa[3]); Intent i = new Intent(getContext(), GeoPointMapActivity.class); i.putExtra(LOCATION, gp); getContext().startActivity(i); } }); addView(mGetLocationButton); if (mUseMaps) { addView(mViewButton); } addView(mAnswerDisplay); } @Override public void clearAnswer() { mStringAnswer.setText(null); mAnswerDisplay.setText(null); mGetLocationButton.setText(StringUtils.getStringSpannableRobust(getContext(), R.string.get_location)); } @Override public IAnswerData getAnswer() { String s = mStringAnswer.getText().toString(); if (s == null || s.equals("")) { return null; } else { try { // segment lat and lon String[] sa = s.split(" "); double gp[] = new double[4]; gp[0] = Double.valueOf(sa[0]); gp[1] = Double.valueOf(sa[1]); gp[2] = Double.valueOf(sa[2]); gp[3] = Double.valueOf(sa[3]); return new GeoPointData(gp); } catch (Exception NumberFormatException) { return null; } } } private String truncateDouble(String s) { DecimalFormat df = new DecimalFormat("#.##"); return df.format(Double.valueOf(s)); } private String formatGps(double coordinates, String type) { String location = Double.toString(coordinates); String degreeSign = "\u00B0"; String degree = location.substring(0, location.indexOf(".")) + degreeSign; location = "0." + location.substring(location.indexOf(".") + 1); double temp = Double.valueOf(location) * 60; location = Double.toString(temp); String mins = location.substring(0, location.indexOf(".")) + "'"; location = "0." + location.substring(location.indexOf(".") + 1); temp = Double.valueOf(location) * 60; location = Double.toString(temp); String secs = location.substring(0, location.indexOf(".")) + '"'; if (type.equalsIgnoreCase("lon")) { if (degree.startsWith("-")) { degree = "W " + degree.replace("-", "") + mins + secs; } else degree = "E " + degree.replace("-", "") + mins + secs; } else { if (degree.startsWith("-")) { degree = "S " + degree.replace("-", "") + mins + secs; } else degree = "N " + degree.replace("-", "") + mins + secs; } return degree; } @Override public void setFocus(Context context) { // Hide the soft keyboard if it's showing. InputMethodManager inputManager = (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE); inputManager.hideSoftInputFromWindow(this.getWindowToken(), 0); } @Override public void setBinaryData(Object answer) { String s = (String)answer; mStringAnswer.setText(s); String[] sa = s.split(" "); mAnswerDisplay.setText( StringUtils.getStringSpannableRobust(getContext(), R.string.latitude) + ": " + formatGps(Double.parseDouble(sa[0]), "lat") + "\n" + StringUtils.getStringSpannableRobust(getContext(), R.string.longitude) + ": " + formatGps(Double.parseDouble(sa[1]), "lon") + "\n" + StringUtils.getStringSpannableRobust(getContext(), R.string.altitude) + ": " + truncateDouble(sa[2]) + "m\n" + StringUtils.getStringSpannableRobust(getContext(), R.string.accuracy) + ": " + truncateDouble(sa[3]) + "m"); // update form relevancies and such widgetEntryChanged(); } @Override public void setOnLongClickListener(OnLongClickListener l) { mViewButton.setOnLongClickListener(l); mGetLocationButton.setOnLongClickListener(l); mStringAnswer.setOnLongClickListener(l); mAnswerDisplay.setOnLongClickListener(l); } @Override public void unsetListeners() { super.unsetListeners(); mViewButton.setOnLongClickListener(null); mGetLocationButton.setOnLongClickListener(null); mStringAnswer.setOnLongClickListener(null); mAnswerDisplay.setOnLongClickListener(null); } @Override public void cancelLongPress() { super.cancelLongPress(); mViewButton.cancelLongPress(); mGetLocationButton.cancelLongPress(); mStringAnswer.cancelLongPress(); mAnswerDisplay.cancelLongPress(); } }