diff --git a/app/src/main/java/de/apps4ics/mountainnavigation/HikePoint.java b/app/src/main/java/de/apps4ics/mountainnavigation/HikePoint.java
new file mode 100644
index 0000000..6cadbd1
--- /dev/null
+++ b/app/src/main/java/de/apps4ics/mountainnavigation/HikePoint.java
@@ -0,0 +1,64 @@
+/**
+ * This file is part of MountainNavigation.
+ *
+ * MountainNavigation is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * MountainNavigation is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MountainNavigation. If not, see .
+ *
+ * @copyright Copyright (c) 2016 Vinzenz Rosenkanz
+ *
+ * @author Vinzenz Rosenkranz
+ */
+
+package de.apps4ics.mountainnavigation;
+
+import android.location.Location;
+
+import org.osmdroid.util.GeoPoint;
+
+public class HikePoint {
+ private long timestamp;
+ private GeoPoint location;
+
+ public HikePoint(Location location, long timestamp) {
+ this(new GeoPoint(location.getLatitude(), location.getLongitude(), location.getAltitude()), timestamp);
+ }
+
+ public HikePoint(GeoPoint geoPoint, long timestamp) {
+ this.location = geoPoint;
+ this.timestamp = timestamp;
+ }
+
+ public HikePoint(GeoPoint geoPoint) {
+ this(geoPoint, System.currentTimeMillis());
+ }
+
+ public HikePoint(Location location) {
+ this(new GeoPoint(location.getLatitude(), location.getLongitude(), location.getAltitude()));
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public GeoPoint getLocation() {
+ return location;
+ }
+
+ public void setLocation(GeoPoint location) {
+ this.location = location;
+ }
+}
diff --git a/app/src/main/java/de/apps4ics/mountainnavigation/MainActivity.java b/app/src/main/java/de/apps4ics/mountainnavigation/MainActivity.java
index d098e7c..dbf9004 100644
--- a/app/src/main/java/de/apps4ics/mountainnavigation/MainActivity.java
+++ b/app/src/main/java/de/apps4ics/mountainnavigation/MainActivity.java
@@ -21,7 +21,9 @@
package de.apps4ics.mountainnavigation;
+import android.app.AlertDialog;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
@@ -43,11 +45,16 @@
import android.support.v7.app.AppCompatActivity;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
+import android.text.Editable;
+import android.text.TextWatcher;
import android.util.Log;
+import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.support.v4.widget.DrawerLayout;
import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
@@ -58,6 +65,7 @@
import org.osmdroid.api.IMapController;
import org.osmdroid.bonuspack.overlays.Marker;
+import org.osmdroid.bonuspack.overlays.Polyline;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
@@ -70,6 +78,7 @@
import de.apps4ics.mountainnavigation.adapters.ImageListAdapter;
import de.apps4ics.mountainnavigation.handlers.DatabaseHandler;
+import de.apps4ics.mountainnavigation.handlers.HikeHandler;
import de.apps4ics.mountainnavigation.handlers.PoiHandler;
import de.apps4ics.mountainnavigation.handlers.WeatherHandler;
import de.apps4ics.mountainnavigation.pois.AddPoiDialog;
@@ -88,7 +97,7 @@
private CharSequence mTitle;
private CharSequence mDrawerTitle;
private static final int GPS_MIN_TIME = 5000;
- private static final int GPS_MIN_DIST = 5;
+ private static final int GPS_MIN_DIST = 10;
private static final int MIN_WEATHER_RELOAD_TIME = 3600000; //1hour, in ms
private static final int MIN_WEATHER_RELOAD_DIST = 5000; //5km, in m
private static final int MIN_POI_RELOAD_TIME = 300000; //5min, in ms
@@ -112,6 +121,7 @@
private DatabaseHandler dbHandler;
private static PoiHandler poiHandler;
private static WeatherHandler weatherHandler;
+ private static HikeHandler hikeHandler;
private long lastWeatherInformation;
private long lastPoiInformation;
@@ -123,6 +133,7 @@
private ActionBarDrawerToggle drawerToggle;
private DrawerLayout drawerLayout;
private LinearLayout poiView;
+ private LinearLayout hikeView;
private LinearLayout menuView;
private ImageView weatherSymbol;
private TextView weatherCity;
@@ -134,6 +145,7 @@
public static ArrayList pathMarkers;
public static OverlayItem imageMarker;
+ private Polyline hikeOverlay;
private String provider;
private static Location mLocation;
@@ -172,16 +184,21 @@
mapController.setZoom(ZOOM_LEVEL);
mapController.setCenter(new GeoPoint(48.52, 9.055));
+ hikeOverlay = new Polyline(this);
+ hikeOverlay.setColor(res.getColor(R.color.polyline_color));
+ mapView.getOverlays().add(hikeOverlay);
+
dbHandler = new DatabaseHandler(this);
poiHandler = new PoiHandler(this, res, mapView);
weatherHandler = new WeatherHandler(this);
+ hikeHandler = new HikeHandler(hikeOverlay);
lastWeatherInformation = lastPoiInformation = 0;
foundLocations = new ArrayList<>();
currentPosition = new Marker(mapView);
- currentPosition.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
+ currentPosition.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER);
currentPosition.setTitle(getString(R.string.osm_marker_title));
currentPosition.setIcon(res.getDrawable(R.drawable.ic_currency_96, null));
@@ -210,6 +227,7 @@
});
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
menuView = (LinearLayout) findViewById(R.id.menuList);
+ hikeView = (LinearLayout) findViewById(R.id.hikeList);
poiView = (LinearLayout) findViewById(R.id.poiList);
weatherSymbol = (ImageView) findViewById(R.id.weather_symbol);
weatherCity = (TextView) findViewById(R.id.weather_city);
@@ -233,6 +251,101 @@
poiView.addView(row);
}
+ final String[] hikeEntries = res.getStringArray(R.array.hikeEntries);
+ ArrayAdapter hikeAdapter = new ArrayAdapter<>(MainActivity.this, R.layout.drawer_list_simple, hikeEntries);
+ for(int i=0; i hikePoints = (ArrayList) hikeHandler.getPoints();
+ if(hikePoints.size() < 2) return;
+
+ LayoutInflater inflater = getLayoutInflater();
+ View hikeDialog = inflater.inflate(R.layout.hike_dialog, null, true);
+ final EditText input = (EditText) hikeDialog.findViewById(R.id.hike_name);
+ TextView lengthView = (TextView) hikeDialog.findViewById(R.id.hike_length);
+ final TextView timeView = (TextView) hikeDialog.findViewById(R.id.hike_time);
+
+ int lengthRest = hikeHandler.getTime();
+ int hours = lengthRest / 3600;
+ lengthRest %= 3600;
+ int minutes = lengthRest / 60;
+ int seconds = lengthRest % 60;
+
+ lengthView.setText(String.format(Locale.getDefault(), "Length so far: %.02fm", hikeHandler.getLength()));
+ timeView.setText(String.format(Locale.getDefault(), "Time so far: %02d:%02d:%02d", hours, minutes, seconds));
+
+ AlertDialog.Builder saveHikeBuilder = new AlertDialog.Builder(MainActivity.this);
+ saveHikeBuilder.setTitle("Save your hike")
+ .setView(hikeDialog)
+ .setPositiveButton("Save hike", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ String name = input.getText().toString().trim();
+ if(!name.equals("")) {
+ hikeHandler.stopRecording();
+ view.setText(hikeEntries[position]);
+ }
+ }
+ })
+ .setNegativeButton("Keep hiking", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ }
+ });
+ final AlertDialog saveHikeDialog = saveHikeBuilder.create();
+ saveHikeDialog.show();
+ final Button saveHikeDialogButton = saveHikeDialog.getButton(AlertDialog.BUTTON_POSITIVE);
+ saveHikeDialogButton.setEnabled(false);
+
+ input.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ if(s.length() > 0) saveHikeDialogButton.setEnabled(true);
+ else saveHikeDialogButton.setEnabled(false);
+ }
+ @Override
+ public void afterTextChanged(Editable s) {
+ }
+ });
+ } else {
+ AlertDialog.Builder startHikeBuilder = new AlertDialog.Builder(MainActivity.this);
+ startHikeBuilder
+ .setTitle("Do you want to start a hike?")
+ .setMessage("This will record a new hike. From now on your locations will be recorded and you can save it afterwards.")
+ .setPositiveButton("Start hike", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ hikeHandler.startRecording();
+ view.setText(res.getString(R.string.hike_title_stop_rec));
+ Toaster(res.getString(R.string.hike_is_recording), true);
+ }
+ })
+ .setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ }
+ });
+ AlertDialog startHikeDialog = startHikeBuilder.create();
+ startHikeDialog.show();
+ }
+ } else if(key.equals(getString(R.string.hike_title_show_key))) {
+ //TODO Open dialog with all hikes around current position (or enter position)
+ }
+ }
+ });
+ menuView.addView(view);
+ }
+
String[] menuEntries = res.getStringArray(R.array.menuEntries);
ArrayAdapter menuAdapter = new ArrayAdapter<>(MainActivity.this, R.layout.drawer_list_simple, menuEntries);
for(int i=0; i.
+ *
+ * @copyright Copyright (c) 2016 Vinzenz Rosenkanz
+ *
+ * @author Vinzenz Rosenkranz
+ */
+
+package de.apps4ics.mountainnavigation.handlers;
+
+import android.location.Location;
+
+import org.osmdroid.bonuspack.overlays.Polyline;
+import org.osmdroid.util.GeoPoint;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.apps4ics.mountainnavigation.HikePoint;
+
+public class HikeHandler {
+ private boolean isRecording;
+ private List timestamps;
+ private List geopoints;
+ private Polyline path;
+ private int time;
+ private float length;
+ private boolean needsUpdate;
+
+ public HikeHandler(Polyline path) {
+ timestamps = new ArrayList<>();
+ geopoints = new ArrayList<>();
+ this.path = path;
+ needsUpdate = false;
+ }
+
+ public boolean isRecording() {
+ return isRecording;
+ }
+
+ public void startRecording() {
+ isRecording = true;
+ }
+
+ public void stopRecording() {
+ isRecording = false;
+ updateProperties();
+ path.setPoints(new ArrayList());
+ }
+
+ private void updateProperties() {
+ if(!needsUpdate) return;
+ needsUpdate = false;
+ if(timestamps.size() < 2) return;
+ time = (int) (timestamps.get(timestamps.size()-1) - timestamps.get(0)) / 1000;
+ GeoPoint first;
+ GeoPoint second = null;
+ float[] results = new float[3];
+ for(GeoPoint p : geopoints) {
+ first = p;
+ if(second != null) {
+ Location.distanceBetween(first.getLatitude(), first.getLongitude(), second.getLatitude(), second.getLongitude(), results);
+ length += results[0];
+ }
+ second = first;
+ }
+ }
+
+ public void addLocation(Location location) {
+ if(!isRecording) return;
+ needsUpdate = true;
+ geopoints.add(new GeoPoint(location.getLatitude(), location.getLongitude(), location.getAltitude()));
+ timestamps.add(System.currentTimeMillis());
+ path.setPoints(geopoints);
+ }
+
+ public List getPoints() {
+ if(geopoints.size() != timestamps.size()) return null;
+ List points = new ArrayList<>();
+ for(int i=0; i
+
+
-
-
+
-
-
-
-
-
+ android:layout_height="wrap_content"
+ android:id="@+id/weather_city"
+ android:gravity="center_vertical"
+ android:textSize="16sp"
+ android:textColor="@color/text_color"
+ android:fontFamily="sans-serif-medium"
+ android:text="@string/no_weather_data_available"/>
+
+
+
-
-
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/hike_dialog.xml b/app/src/main/res/layout/hike_dialog.xml
new file mode 100644
index 0000000..91d53bf
--- /dev/null
+++ b/app/src/main/res/layout/hike_dialog.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml
index 07e705f..19d9d67 100644
--- a/app/src/main/res/values-de-rDE/strings.xml
+++ b/app/src/main/res/values-de-rDE/strings.xml
@@ -76,6 +76,8 @@
Dein Standort
Latitude: %1$.03f<br/>Longitude: %2$.03f<br/>Höhe: %3$dm<br/>Hinzugefügt: %4$s
Keine Wetterdaten verfügbar
+ Nehme auf…
+ Aufnahme stoppen
de
H:m
@@ -130,6 +132,10 @@
- Einstellungen
- Über
+
+ - Wanderung aufnehmen
+ - Wanderungen anzeigen
+
- Klein
- Mittel
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 376ea89..77296f0 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -24,4 +24,5 @@
#AA000000
#FF000000
#AFB9B9B9
+ #AA0E84F1
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 96182bf..609637d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -78,6 +78,8 @@
Latitude: %1$.03f<br/>Longitude: %2$.03f<br/>Altitude: %3$d meters<br/>Added: %4$s
%1$s, %2$s
No weather data available
+ Recording…
+ Stop recording
en
h:m a
@@ -119,6 +121,8 @@
about
settings
download
+ showHikes
+ recordHike
hints
dispHints
maxHotTemp
@@ -160,6 +164,14 @@
- @string/menu_title_settings_key
- @string/menu_title_about_key
+
+ - Record hike
+ - Show hikes
+
+
+ - @string/hike_title_record_key
+ - @string/hike_title_show_key
+
- - OpenStreetMap: https://www.openstreetmap.org/
- - OpenWeatherMap: https://openweathermap.org/