/* * 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 org.odk.collect.android.widgets; import java.text.DecimalFormat; import org.javarosa.core.model.data.GeoPointData; import org.javarosa.core.model.data.IAnswerData; import org.javarosa.form.api.FormEntryPrompt; import org.odk.collect.android.R; import org.odk.collect.android.activities.FormEntryActivity; import org.odk.collect.android.activities.GeoPointActivity; import org.odk.collect.android.activities.GeoPointMapActivity; import org.odk.collect.android.utilities.StringUtils; import android.app.Activity; import android.content.Context; import android.content.Intent; 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.TableLayout; import android.widget.TextView; /** * 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 implements IBinaryWidget { private Button mGetLocationButton; private Button mViewButton; private TextView mStringAnswer; private TextView mAnswerDisplay; private boolean mWaitingForData; private boolean mUseMaps; private String mAppearance; public static String LOCATION = "gp"; public GeoPointWidget(Context context, FormEntryPrompt prompt) { super(context, prompt); mWaitingForData = false; mUseMaps = false; mAppearance = prompt.getAppearanceHint(); setOrientation(LinearLayout.VERTICAL); TableLayout.LayoutParams params = new TableLayout.LayoutParams(); params.setMargins(7, 5, 7, 5); mGetLocationButton = new Button(getContext()); mGetLocationButton.setPadding(20, 20, 20, 20); mGetLocationButton.setText(StringUtils.getStringRobust(getContext(), R.string.get_location)); mGetLocationButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, mAnswerFontsize); mGetLocationButton.setEnabled(!prompt.isReadOnly()); mGetLocationButton.setLayoutParams(params); // setup play button mViewButton = new Button(getContext()); mViewButton.setText(StringUtils.getStringRobust(getContext(), R.string.show_location)); mViewButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, mAnswerFontsize); mViewButton.setPadding(20, 20, 20, 20); mViewButton.setLayoutParams(params); // on play, launch the appropriate viewer mViewButton.setOnClickListener(new View.OnClickListener() { /* * (non-Javadoc) * @see android.view.View.OnClickListener#onClick(android.view.View) */ @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]).doubleValue(); gp[1] = Double.valueOf(sa[1]).doubleValue(); gp[2] = Double.valueOf(sa[2]).doubleValue(); gp[3] = Double.valueOf(sa[3]).doubleValue(); Intent i = new Intent(getContext(), GeoPointMapActivity.class); i.putExtra(LOCATION, gp); ((Activity) getContext()).startActivity(i); } }); mStringAnswer = new TextView(getContext()); mAnswerDisplay = new TextView(getContext()); mAnswerDisplay.setTextSize(TypedValue.COMPLEX_UNIT_DIP, mAnswerFontsize); mAnswerDisplay.setGravity(Gravity.CENTER); String s = prompt.getAnswerText(); if (s != null && !s.equals("")) { mGetLocationButton.setText(StringUtils.getStringRobust(getContext(), R.string.replace_location)); setBinaryData(s); mViewButton.setEnabled(true); } else { mViewButton.setEnabled(false); } // use maps or not if (mAppearance != null && mAppearance.equalsIgnoreCase("maps")) { try { // do google maps exist on the device Class.forName("com.google.android.maps.MapActivity"); mUseMaps = true; } catch (ClassNotFoundException e) { mUseMaps = false; } } // when you press the button mGetLocationButton.setOnClickListener(new View.OnClickListener() { /* * (non-Javadoc) * @see android.view.View.OnClickListener#onClick(android.view.View) */ @Override public void onClick(View v) { Intent i = null; if (mUseMaps) { i = new Intent(getContext(), GeoPointMapActivity.class); } else { i = new Intent(getContext(), GeoPointActivity.class); } ((Activity) getContext()).startActivityForResult(i, FormEntryActivity.LOCATION_CAPTURE); mWaitingForData = true; } }); // finish complex layout // retrieve answer from data model and update ui addView(mGetLocationButton); if (mUseMaps) { addView(mViewButton); } addView(mAnswerDisplay); } /* * (non-Javadoc) * @see org.odk.collect.android.widgets.QuestionWidget#clearAnswer() */ @Override public void clearAnswer() { mStringAnswer.setText(null); mAnswerDisplay.setText(null); mGetLocationButton.setText(StringUtils.getStringRobust(getContext(), R.string.get_location)); } /* * (non-Javadoc) * @see org.odk.collect.android.widgets.QuestionWidget#getAnswer() */ @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]).doubleValue(); gp[1] = Double.valueOf(sa[1]).doubleValue(); gp[2] = Double.valueOf(sa[2]).doubleValue(); gp[3] = Double.valueOf(sa[3]).doubleValue(); 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; } /* * (non-Javadoc) * @see org.odk.collect.android.widgets.QuestionWidget#setFocus(android.content.Context) */ @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); } /* * (non-Javadoc) * @see org.odk.collect.android.widgets.IBinaryWidget#setBinaryData(java.lang.Object) */ @Override public void setBinaryData(Object answer) { String s = (String) answer; mStringAnswer.setText(s); String[] sa = s.split(" "); mAnswerDisplay.setText(StringUtils.getStringRobust(getContext(), R.string.latitude) + ": " + formatGps(Double.parseDouble(sa[0]), "lat") + "\n" + StringUtils.getStringRobust(getContext(), R.string.longitude) + ": " + formatGps(Double.parseDouble(sa[1]), "lon") + "\n" + StringUtils.getStringRobust(getContext(), R.string.altitude) + ": " + truncateDouble(sa[2]) + "m\n" + StringUtils.getStringRobust(getContext(), R.string.accuracy) + ": " + truncateDouble(sa[3]) + "m"); mWaitingForData = false; } /* * (non-Javadoc) * @see org.odk.collect.android.widgets.IBinaryWidget#isWaitingForBinaryData() */ @Override public boolean isWaitingForBinaryData() { return mWaitingForData; } /* * (non-Javadoc) * @see org.odk.collect.android.widgets.QuestionWidget#setOnLongClickListener(android.view.View.OnLongClickListener) */ @Override public void setOnLongClickListener(OnLongClickListener l) { mViewButton.setOnLongClickListener(l); mGetLocationButton.setOnLongClickListener(l); mStringAnswer.setOnLongClickListener(l); mAnswerDisplay.setOnLongClickListener(l); } /* * (non-Javadoc) * @see org.odk.collect.android.widgets.QuestionWidget#cancelLongPress() */ @Override public void cancelLongPress() { super.cancelLongPress(); mViewButton.cancelLongPress(); mGetLocationButton.cancelLongPress(); mStringAnswer.cancelLongPress(); mAnswerDisplay.cancelLongPress(); } }