diff --git a/app/build.gradle b/app/build.gradle index 6e594a8..62da33b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,5 +1,32 @@ +/* + * Copyright (c) 2019 Jannis Scheibe + * + * This file is part of FitoTrack + * + * FitoTrack 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. + * + * FitoTrack 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 this program. If not, see . + */ + apply plugin: 'com.android.application' +allprojects { + dependencies { + repositories { + jcenter() + } + } +} + android { compileSdkVersion 28 buildToolsVersion "29.0.1" @@ -20,9 +47,19 @@ android { } dependencies { + def room_version = "2.2.0-alpha02" + implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support.constraint:constraint-layout:1.1.3' - implementation "androidx.room:room-runtime:2.2.0-alpha02" + implementation "androidx.room:room-runtime:$room_version" + implementation 'org.mapsforge:mapsforge-core:0.11.0' + implementation 'org.mapsforge:mapsforge-map:0.11.0' + implementation 'org.mapsforge:mapsforge-map-reader:0.11.0' + implementation 'org.mapsforge:mapsforge-themes:0.11.0' + implementation 'org.mapsforge:mapsforge-map-android:0.11.0' + implementation 'com.caverock:androidsvg:1.3' + implementation 'net.sf.kxml:kxml2:2.3.0' + annotationProcessor "androidx.room:room-compiler:$room_version" implementation 'androidx.recyclerview:recyclerview:1.0.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a67c4e9..1a01d55 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,7 +1,30 @@ + + + + + + + * + * This file is part of FitoTrack + * + * FitoTrack 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. + * + * FitoTrack 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 this program. If not, see . + */ + package de.tadris.fitness; +import android.Manifest; import android.app.Activity; +import android.content.pm.PackageManager; +import android.location.Location; import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.ViewGroup; -public class RecordWorkoutActivity extends Activity { +import androidx.core.app.ActivityCompat; + +import org.mapsforge.core.model.LatLong; +import org.mapsforge.map.android.graphics.AndroidGraphicFactory; +import org.mapsforge.map.android.util.AndroidUtil; +import org.mapsforge.map.android.view.MapView; +import org.mapsforge.map.layer.cache.TileCache; +import org.mapsforge.map.layer.download.TileDownloadLayer; + +import de.tadris.fitness.data.Workout; +import de.tadris.fitness.location.LocationListener; +import de.tadris.fitness.location.MyLocationOverlay; +import de.tadris.fitness.location.WorkoutRecorder; +import de.tadris.fitness.map.HumanitarianTileSource; + +public class RecordWorkoutActivity extends Activity implements LocationListener.LocationChangeListener { + + MapView mapView; + MyLocationOverlay locationOverlay; + TileDownloadLayer downloadLayer; + WorkoutRecorder recorder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_record_workout); + + this.mapView= new MapView(this); + + mapView.setZoomLevelMin((byte) 18); + mapView.setZoomLevelMax((byte) 18); + mapView.setBuiltInZoomControls(false); + + TileCache tileCache = AndroidUtil.createTileCache(this, "mapcache", mapView.getModel().displayModel.getTileSize(), 1f, this.mapView.getModel().frameBufferModel.getOverdrawFactor(), true); + + HumanitarianTileSource tileSource = HumanitarianTileSource.INSTANCE; + tileSource.setUserAgent("mapsforge-android"); + downloadLayer = new TileDownloadLayer(tileCache, mapView.getModel().mapViewPosition, tileSource, AndroidGraphicFactory.INSTANCE); + + mapView.getLayerManager().getLayers().add(downloadLayer); + + locationOverlay= new MyLocationOverlay(Instance.getInstance(this).locationListener, getDrawable(R.drawable.location_marker)); + + mapView.getLayerManager().redrawLayers(); + + mapView.setZoomLevel((byte) 18); + mapView.setCenter(new LatLong(52, 13)); + + ((ViewGroup)findViewById(R.id.recordMapViewrRoot)).addView(mapView); + + checkPermissions(); + + recorder= new WorkoutRecorder(this, Workout.WORKOUT_TYPE_RUNNING); + recorder.start(); + } + + private void stopAndSave(){ + recorder.stop(); + if(recorder.getSampleCount() > 3){ + recorder.save(); + } + finish(); + } + + void checkPermissions(){ + if (!hasPermission()) { + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 10); + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 10); + } + } + + public boolean hasPermission(){ + return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED + || ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED; + } + + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + if (hasPermission()) { + Instance.getInstance(this).locationListener.enableMyLocation(); + } + } + + @Override + public void onLocationChange(Location location) { + mapView.getModel().mapViewPosition.animateTo(LocationListener.locationToLatLong(location)); + locationOverlay.setPosition(location.getLatitude(), location.getLongitude(), location.getAccuracy()); + } + + @Override + protected void onDestroy() { + recorder.stop(); + mapView.destroyAll(); + AndroidGraphicFactory.clearResourceMemoryCache(); + super.onDestroy(); + } + + @Override + public void onPause(){ + super.onPause(); + downloadLayer.onPause(); + Instance.getInstance(this).locationListener.unregisterLocationChangeListeners(this); + } + + public void onResume(){ + super.onResume(); + downloadLayer.onResume(); + Instance.getInstance(this).locationListener.registerLocationChangeListeners(this); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.record_menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + if(id == R.id.actionRecordingStop){ + stopAndSave(); + return true; + } + return super.onOptionsItemSelected(item); } - - void onMenuCreate(){ - - } } diff --git a/app/src/main/java/de/tadris/fitness/WorkoutAdapter.java b/app/src/main/java/de/tadris/fitness/WorkoutAdapter.java index 6a8dfee..e1fc4df 100644 --- a/app/src/main/java/de/tadris/fitness/WorkoutAdapter.java +++ b/app/src/main/java/de/tadris/fitness/WorkoutAdapter.java @@ -1,3 +1,22 @@ +/* + * Copyright (c) 2019 Jannis Scheibe + * + * This file is part of FitoTrack + * + * FitoTrack 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. + * + * FitoTrack 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 this program. If not, see . + */ + package de.tadris.fitness; import android.view.LayoutInflater; @@ -45,7 +64,7 @@ public class WorkoutAdapter extends RecyclerView.Adapter + * + * This file is part of FitoTrack + * + * FitoTrack 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. + * + * FitoTrack 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 this program. If not, see . + */ + +package de.tadris.fitness.data; + +import java.util.List; + +import de.tadris.fitness.Instance; + +public class WorkoutManager { + + public static void insertWorkout(Instance instance, Workout workout, List samples){ + workout.id= System.currentTimeMillis(); + + // Calculating values + double length= 0; + for(int i= 1; i < samples.size(); i++){ + length+= samples.get(i - 1).toLatLong().sphericalDistance(samples.get(i).toLatLong()); + } + workout.length= (int)length; + workout.avgSpeed= ((double) workout.length / 1000) / ((double) workout.getTime() / 1000); + workout.avgPace= (double)(workout.getTime() / 1000 / 60) / ((double) workout.length / 1000); + + // Setting workoutId in the samples + int i= 0; + for(WorkoutSample sample : samples){ + i++; + sample.id= workout.id + i; + sample.workoutId= workout.id; + } + + // Saving workout and samples + instance.db.workoutDao().insertWorkoutAndSamples(workout, samples.toArray(new WorkoutSample[0])); + + } + +} diff --git a/app/src/main/java/de/tadris/fitness/data/WorkoutSample.java b/app/src/main/java/de/tadris/fitness/data/WorkoutSample.java index 3fb3b01..01117c3 100644 --- a/app/src/main/java/de/tadris/fitness/data/WorkoutSample.java +++ b/app/src/main/java/de/tadris/fitness/data/WorkoutSample.java @@ -24,6 +24,8 @@ import androidx.room.Entity; import androidx.room.ForeignKey; import androidx.room.PrimaryKey; +import org.mapsforge.core.model.LatLong; + import static androidx.room.ForeignKey.CASCADE; @Entity(tableName = "workout_sample", @@ -48,5 +50,9 @@ public class WorkoutSample{ public double speed; + public LatLong toLatLong(){ + return new LatLong(lat, lon); + } + } diff --git a/app/src/main/java/de/tadris/fitness/location/LocationListener.java b/app/src/main/java/de/tadris/fitness/location/LocationListener.java new file mode 100644 index 0000000..d04769f --- /dev/null +++ b/app/src/main/java/de/tadris/fitness/location/LocationListener.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2019 Jannis Scheibe + * + * This file is part of FitoTrack + * + * FitoTrack 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. + * + * FitoTrack 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 this program. If not, see . + */ + +package de.tadris.fitness.location; + +import android.Manifest; +import android.content.Context; +import android.content.pm.PackageManager; +import android.location.Location; +import android.location.LocationManager; +import android.os.Bundle; + +import androidx.core.app.ActivityCompat; + +import org.mapsforge.core.model.LatLong; + +import java.util.ArrayList; +import java.util.List; + +public class LocationListener implements android.location.LocationListener { + + public static LatLong static_lastLocation; + + /** + * @param location the location whose geographical coordinates should be converted. + * @return a new LatLong with the geographical coordinates taken from the given location. + */ + public static LatLong locationToLatLong(Location location) { + return new LatLong(location.getLatitude(), location.getLongitude()); + } + + private Context activity; + private Location lastLocation; + private final LocationManager locationManager; + private boolean myLocationEnabled; + + public LocationListener(Context context) { + super(); + this.activity= context; + this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + } + + + /** + * Stops the receiving of location updates. Has no effect if location updates are already disabled. + */ + public synchronized void disableMyLocation() { + if (this.myLocationEnabled) { + this.myLocationEnabled = false; + try { + this.locationManager.removeUpdates(this); + } catch (RuntimeException runtimeException) { + // do we need to catch security exceptions for this call on Android 6? + } + } + } + + public synchronized void enableMyLocation() { + enableBestAvailableProvider(); + } + + /** + * @return the most-recently received location fix (might be null). + */ + public synchronized Location getLastLocation() { + return this.lastLocation; + } + + /** + * @return true if the receiving of location updates is currently enabled, false otherwise. + */ + public synchronized boolean isMyLocationEnabled() { + return this.myLocationEnabled; + } + + @Override + public void onLocationChanged(Location location) { + + synchronized (this) { + this.lastLocation = location; + + LatLong latLong = locationToLatLong(location); + static_lastLocation= latLong; + + for(LocationChangeListener listener : this.locationChangeListeners){ + listener.onLocationChange(location); + } + } + } + + @Override + public void onProviderDisabled(String provider) { + enableBestAvailableProvider(); + } + + @Override + public void onProviderEnabled(String provider) { + enableBestAvailableProvider(); + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + // do nothing + } + + private void enableBestAvailableProvider() { + disableMyLocation(); + + boolean result = false; + for (String provider : this.locationManager.getProviders(true)) { + if (LocationManager.GPS_PROVIDER.equals(provider) || LocationManager.NETWORK_PROVIDER.equals(provider)) { + result = true; + if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + return; + } + this.locationManager.requestLocationUpdates(provider, 0, 0, this); + Location location= this.locationManager.getLastKnownLocation(provider); + if(location != null){ + onLocationChanged(location); + } + } + } + this.myLocationEnabled = result; + } + + private List locationChangeListeners= new ArrayList<>(); + + public void registerLocationChangeListeners(LocationChangeListener listener){ + if(locationChangeListeners.size() == 0){ + enableMyLocation(); + } + locationChangeListeners.add(listener); + } + + public void unregisterLocationChangeListeners(LocationChangeListener listener){ + locationChangeListeners.remove(listener); + if(locationChangeListeners.size() == 0){ + disableMyLocation(); + } + } + + public interface LocationChangeListener{ + void onLocationChange(Location location); + } + +} diff --git a/app/src/main/java/de/tadris/fitness/location/MyLocationOverlay.java b/app/src/main/java/de/tadris/fitness/location/MyLocationOverlay.java new file mode 100644 index 0000000..7393240 --- /dev/null +++ b/app/src/main/java/de/tadris/fitness/location/MyLocationOverlay.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2019 Jannis Scheibe + * + * This file is part of FitoTrack + * + * FitoTrack 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. + * + * FitoTrack 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 this program. If not, see . + */ + +package de.tadris.fitness.location; + +import android.graphics.drawable.Drawable; + +import org.mapsforge.core.graphics.Canvas; +import org.mapsforge.core.graphics.Paint; +import org.mapsforge.core.graphics.Style; +import org.mapsforge.core.model.BoundingBox; +import org.mapsforge.core.model.LatLong; +import org.mapsforge.core.model.Point; +import org.mapsforge.map.android.graphics.AndroidGraphicFactory; +import org.mapsforge.map.layer.Layer; +import org.mapsforge.map.layer.overlay.Circle; +import org.mapsforge.map.layer.overlay.Marker; + +public class MyLocationOverlay extends Layer { + + private final Circle circle; + private final Marker marker; + private final LocationListener locationListener; + + private static Paint getDefaultFixedPixelCircleFill() { + return getPaint(AndroidGraphicFactory.INSTANCE.createColor(255, 0, 0, 255), 0, Style.FILL); + } + + private static Paint getDefaultOuterFixedPixelCircleFill(){ + return getPaint(AndroidGraphicFactory.INSTANCE.createColor(30, 30, 30, 255), 0, Style.FILL); + } + + private static Paint getDefaultFixedPixelCircleStroke() { + return getPaint(AndroidGraphicFactory.INSTANCE.createColor(255, 255, 255, 255), 7, Style.STROKE); + } + + private static Paint getPaint(int color, int strokeWidth, Style style) { + Paint paint = AndroidGraphicFactory.INSTANCE.createPaint(); + paint.setColor(color); + paint.setStrokeWidth(strokeWidth); + paint.setStyle(style); + return paint; + } + + public MyLocationOverlay(LocationListener locationListener, Drawable icon) { + this.locationListener= locationListener; + this.circle= new Circle(null, 0f, getDefaultFixedPixelCircleFill(), null); + this.marker= new Marker(null, AndroidGraphicFactory.convertToBitmap(icon), 26, 26); + } + + @Override + public synchronized void draw(BoundingBox boundingBox, byte zoomLevel, Canvas canvas, Point topLeftPoint) { + if (this.circle != null) { + this.circle.draw(boundingBox, zoomLevel, canvas, topLeftPoint); + } + this.marker.draw(boundingBox, zoomLevel, canvas, topLeftPoint); + } + + @Override + protected void onAdd() { + this.circle.setDisplayModel(this.displayModel); + this.marker.setDisplayModel(this.displayModel); + } + + @Override + public void onDestroy() { + this.marker.onDestroy(); + } + + public void setPosition(double latitude, double longitude, float accuracy) { + synchronized (this) { + LatLong latLong = new LatLong(latitude, longitude); + this.marker.setLatLong(latLong); + if (this.circle != null) { + this.circle.setLatLong(latLong); + this.circle.setRadius(accuracy); + } + requestRedraw(); + } + } + +} diff --git a/app/src/main/java/de/tadris/fitness/location/WorkoutRecorder.java b/app/src/main/java/de/tadris/fitness/location/WorkoutRecorder.java new file mode 100644 index 0000000..23de5a9 --- /dev/null +++ b/app/src/main/java/de/tadris/fitness/location/WorkoutRecorder.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2019 Jannis Scheibe + * + * This file is part of FitoTrack + * + * FitoTrack 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. + * + * FitoTrack 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 this program. If not, see . + */ + +package de.tadris.fitness.location; + +import android.content.Context; +import android.location.Location; +import android.util.Log; + +import org.mapsforge.core.model.LatLong; + +import java.util.ArrayList; +import java.util.List; + +import de.tadris.fitness.Instance; +import de.tadris.fitness.data.Workout; +import de.tadris.fitness.data.WorkoutManager; +import de.tadris.fitness.data.WorkoutSample; + +public class WorkoutRecorder implements LocationListener.LocationChangeListener { + + private static final int MIN_DISTANCE= 5; + + private Context context; + private Workout workout; + private RecordingState state; + private List samples= new ArrayList<>(); + private long time= 0; + private long lastResume; + + public WorkoutRecorder(Context context, String workoutType) { + this.context= context; + this.state= RecordingState.IDLE; + + this.workout= new Workout(); + this.workout.workoutType= workoutType; + } + + public void start(){ + if(state == RecordingState.IDLE){ + Log.i("Recorder", ""); + workout.start= System.currentTimeMillis(); + resume(); + }else if(state == RecordingState.PAUSED){ + resume(); + }else if(state != RecordingState.RUNNING){ + throw new IllegalStateException("Cannot start or resume recording. state = " + state); + } + } + + private void resume(){ + state= RecordingState.RUNNING; + lastResume= System.currentTimeMillis(); + Instance.getInstance(context).locationListener.registerLocationChangeListeners(this); + } + + public void pause(){ + if(state == RecordingState.RUNNING){ + state= RecordingState.PAUSED; + time+= System.currentTimeMillis() - lastResume; + Instance.getInstance(context).locationListener.unregisterLocationChangeListeners(this); + } + } + + public void stop(){ + pause(); + workout.end= System.currentTimeMillis(); + state= RecordingState.STOPPED; + } + + public void save(){ + if(state != RecordingState.STOPPED){ + throw new IllegalStateException("Cannot save recording, recorder was not stopped. state = " + state); + } + WorkoutManager.insertWorkout(Instance.getInstance(context), workout, samples); + } + + public int getSampleCount(){ + return samples.size(); + } + + @Override + public void onLocationChange(Location location) { + if(state == RecordingState.RUNNING){ + if(getSampleCount() > 0){ + WorkoutSample lastSample= samples.get(samples.size() - 1); + if(LocationListener.locationToLatLong(location).sphericalDistance(new LatLong(lastSample.lat, lastSample.lon)) < MIN_DISTANCE){ + return; + } + } + WorkoutSample sample= new WorkoutSample(); + sample.lat= location.getLatitude(); + sample.lon= location.getLongitude(); + sample.speed= location.getSpeed(); + sample.time= location.getTime(); + samples.add(sample); + } + } + + + enum RecordingState{ + IDLE, RUNNING, PAUSED, STOPPED + } + +} diff --git a/app/src/main/java/de/tadris/fitness/map/HumanitarianTileSource.java b/app/src/main/java/de/tadris/fitness/map/HumanitarianTileSource.java new file mode 100644 index 0000000..8e2ec5c --- /dev/null +++ b/app/src/main/java/de/tadris/fitness/map/HumanitarianTileSource.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019 Jannis Scheibe + * + * This file is part of FitoTrack + * + * FitoTrack 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. + * + * FitoTrack 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 this program. If not, see . + */ + +package de.tadris.fitness.map; + +import org.mapsforge.core.model.Tile; +import org.mapsforge.map.layer.download.tilesource.AbstractTileSource; + +import java.net.MalformedURLException; +import java.net.URL; + +public class HumanitarianTileSource extends AbstractTileSource { + + public static HumanitarianTileSource INSTANCE= new HumanitarianTileSource(new String[]{"tile-a.openstreetmap.fr", "tile-b.openstreetmap.fr", "tile-c.openstreetmap.fr"}, 443); + + private static final int PARALLEL_REQUESTS_LIMIT = 8; + private static final String PROTOCOL = "https"; + private static final int ZOOM_LEVEL_MAX = 18; + private static final int ZOOM_LEVEL_MIN = 0; + + public HumanitarianTileSource(String[] hostNames, int port) { + super(hostNames, port); + defaultTimeToLive = 864000000; // Ten days + } + + @Override + public int getParallelRequestsLimit() { + return PARALLEL_REQUESTS_LIMIT; + } + + @Override + public URL getTileUrl(Tile tile) throws MalformedURLException { + + return new URL(PROTOCOL, getHostName(), this.port, "/hot/" + tile.zoomLevel + '/' + tile.tileX + '/' + tile.tileY + ".png"); + } + + @Override + public byte getZoomLevelMax() { + return ZOOM_LEVEL_MAX; + } + + @Override + public byte getZoomLevelMin() { + return ZOOM_LEVEL_MIN; + } + + @Override + public boolean hasAlpha() { + return false; + } +} diff --git a/app/src/main/java/de/tadris/fitness/map/InternalRenderTheme.java b/app/src/main/java/de/tadris/fitness/map/InternalRenderTheme.java new file mode 100644 index 0000000..a3c6e53 --- /dev/null +++ b/app/src/main/java/de/tadris/fitness/map/InternalRenderTheme.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 Jannis Scheibe + * + * This file is part of FitoTrack + * + * FitoTrack 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. + * + * FitoTrack 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 this program. If not, see . + */ + +package de.tadris.fitness.map; + +import org.mapsforge.map.rendertheme.XmlRenderTheme; +import org.mapsforge.map.rendertheme.XmlRenderThemeMenuCallback; + +import java.io.InputStream; + +/** + * Enumeration of all internal rendering themes. + */ +public enum InternalRenderTheme implements XmlRenderTheme { + + OLD("/assets/rendertheme/default.xml"), + DEFAULT("/assets/rendertheme/osmarender.xml"); + + private final String path; + private XmlRenderThemeMenuCallback callback; + + InternalRenderTheme(String path) { + this.path = path; + } + + @Override + public XmlRenderThemeMenuCallback getMenuCallback() { + return callback; + } + + /** + * @return the prefix for all relative resource paths. + */ + @Override + public String getRelativePathPrefix() { + return "/assets/"; + } + + @Override + public InputStream getRenderThemeAsStream() { + return getClass().getResourceAsStream(this.path); + } + + @Override + public void setMenuCallback(XmlRenderThemeMenuCallback menuCallback) { + callback= menuCallback; + } +} diff --git a/app/src/main/java/de/tadris/fitness/util/UnitUtils.java b/app/src/main/java/de/tadris/fitness/util/UnitUtils.java index fca11bf..d13752a 100644 --- a/app/src/main/java/de/tadris/fitness/util/UnitUtils.java +++ b/app/src/main/java/de/tadris/fitness/util/UnitUtils.java @@ -1,6 +1,23 @@ -package de.tadris.fitness.util; +/* + * Copyright (c) 2019 Jannis Scheibe + * + * This file is part of FitoTrack + * + * FitoTrack 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. + * + * FitoTrack 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 this program. If not, see . + */ -import android.content.Context; +package de.tadris.fitness.util; public class UnitUtils { @@ -17,4 +34,30 @@ public class UnitUtils { } } + /** + * + * @param distance Distance in meters + * @return String in preferred unit + */ + public static String getDistance(int distance){ + if(distance >= 1000){ + return getDistanceInKilometers((double)distance); + }else{ + return getDistanceInMeters(distance); + } + } + + public static String getDistanceInMeters(int distance){ + return distance + "m"; + } + + public static String getDistanceInKilometers(double distance){ + return round(distance / 1000, 1) + "km"; + } + + public static double round(double d, int count){ + return (double)Math.round(d * Math.pow(10, count)) / count; + } + + } diff --git a/app/src/main/res/drawable/ic_record_24dp.xml b/app/src/main/res/drawable/ic_record_24dp.xml new file mode 100644 index 0000000..802b70a --- /dev/null +++ b/app/src/main/res/drawable/ic_record_24dp.xml @@ -0,0 +1,28 @@ + + + + + diff --git a/app/src/main/res/drawable/location_marker.png b/app/src/main/res/drawable/location_marker.png new file mode 100644 index 0000000..a868f9d Binary files /dev/null and b/app/src/main/res/drawable/location_marker.png differ diff --git a/app/src/main/res/layout/activity_record_workout.xml b/app/src/main/res/layout/activity_record_workout.xml index f7e2426..6088777 100644 --- a/app/src/main/res/layout/activity_record_workout.xml +++ b/app/src/main/res/layout/activity_record_workout.xml @@ -1,9 +1,61 @@ - + ~ + ~ This file is part of FitoTrack + ~ + ~ FitoTrack 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. + ~ + ~ FitoTrack 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 this program. If not, see . + --> + + - \ No newline at end of file + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/list_workout_menu.xml b/app/src/main/res/menu/list_workout_menu.xml index 5ff6595..39c66ac 100644 --- a/app/src/main/res/menu/list_workout_menu.xml +++ b/app/src/main/res/menu/list_workout_menu.xml @@ -1,7 +1,27 @@ + + \ No newline at end of file diff --git a/app/src/main/res/menu/record_menu.xml b/app/src/main/res/menu/record_menu.xml new file mode 100644 index 0000000..e2b7fa8 --- /dev/null +++ b/app/src/main/res/menu/record_menu.xml @@ -0,0 +1,27 @@ + + + + + + + \ 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 55b358c..eed3063 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,4 +1,24 @@ + + FitoTrack Add + Stop