diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1501da5..a2929f3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -26,6 +26,7 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/java/de/tadris/fitness/Instance.java b/app/src/main/java/de/tadris/fitness/Instance.java
index 517a295..4257edc 100644
--- a/app/src/main/java/de/tadris/fitness/Instance.java
+++ b/app/src/main/java/de/tadris/fitness/Instance.java
@@ -23,6 +23,9 @@ import android.content.Context;
import androidx.room.Room;
+import java.util.ArrayList;
+import java.util.List;
+
import de.tadris.fitness.data.AppDatabase;
import de.tadris.fitness.location.LocationListener;
@@ -40,14 +43,13 @@ public class Instance {
}
public AppDatabase db;
- public LocationListener locationListener;
public UserPreferences userPreferences;
+ public List locationChangeListeners= new ArrayList<>();
private Instance(Context context) {
db = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME)
.allowMainThreadQueries()
.build();
- locationListener= new LocationListener(context);
userPreferences= new UserPreferences();
}
}
diff --git a/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java b/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java
index 84a160c..09e3728 100644
--- a/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java
+++ b/app/src/main/java/de/tadris/fitness/activity/RecordWorkoutActivity.java
@@ -20,8 +20,10 @@
package de.tadris.fitness.activity;
import android.Manifest;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
@@ -66,6 +68,7 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location
boolean isResumed= false;
private Handler mHandler= new Handler();
PowerManager.WakeLock wakeLock;
+ Intent locationListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -92,11 +95,16 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location
startUpdater();
acquireWakelock();
+
+ Instance.getInstance(this).locationChangeListeners.add(this);
+
+ startListener();
+
}
private void acquireWakelock(){
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
- PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "de.tadris.fitotrack:workout_recorder");
+ wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "de.tadris.fitotrack:workout_recorder");
wakeLock.acquire(1000*60*120);
}
@@ -163,7 +171,24 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (hasPermission()) {
- Instance.getInstance(this).locationListener.enableMyLocation();
+ startListener();
+ }
+ }
+
+ public void stopListener(){
+ stopService(locationListener);
+ }
+
+ public void startListener(){
+ if(locationListener == null){
+ locationListener= new Intent(this, LocationListener.class);
+ }else{
+ stopListener();
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ startForegroundService(locationListener);
+ }else{
+ startService(locationListener);
}
}
@@ -184,20 +209,20 @@ public class RecordWorkoutActivity extends FitoTrackActivity implements Location
if(wakeLock.isHeld()){
wakeLock.release();
}
+ Instance.getInstance(this).locationChangeListeners.remove(this);
+ stopListener();
}
@Override
public void onPause(){
super.onPause();
downloadLayer.onPause();
- Instance.getInstance(this).locationListener.unregisterLocationChangeListeners(this);
isResumed= false;
}
public void onResume(){
super.onResume();
downloadLayer.onResume();
- Instance.getInstance(this).locationListener.registerLocationChangeListeners(this);
isResumed= true;
}
diff --git a/app/src/main/java/de/tadris/fitness/data/WorkoutManager.java b/app/src/main/java/de/tadris/fitness/data/WorkoutManager.java
index 810bdc2..1988af9 100644
--- a/app/src/main/java/de/tadris/fitness/data/WorkoutManager.java
+++ b/app/src/main/java/de/tadris/fitness/data/WorkoutManager.java
@@ -20,6 +20,7 @@
package de.tadris.fitness.data;
import android.content.Context;
+import android.util.Log;
import java.util.List;
@@ -34,6 +35,16 @@ public class WorkoutManager {
workout.id= System.currentTimeMillis();
+ // Delete Samples with same time
+ for(int i= samples.size()-2; i >= 0; i--){
+ WorkoutSample sample= samples.get(i);
+ WorkoutSample lastSample= samples.get(i+1);
+ if(sample.absoluteTime == lastSample.absoluteTime){
+ samples.remove(lastSample);
+ Log.i("WorkoutManager", "Removed samples at " + sample.absoluteTime + " rel: " + sample.relativeTime + "; " + lastSample.relativeTime);
+ }
+ }
+
// Calculating values
double length= 0;
for(int i= 1; i < samples.size(); i++){
diff --git a/app/src/main/java/de/tadris/fitness/location/LocationListener.java b/app/src/main/java/de/tadris/fitness/location/LocationListener.java
index e7ad0cb..ffd3516 100644
--- a/app/src/main/java/de/tadris/fitness/location/LocationListener.java
+++ b/app/src/main/java/de/tadris/fitness/location/LocationListener.java
@@ -1,3 +1,4 @@
+
/*
* Copyright (c) 2019 Jannis Scheibe
*
@@ -19,23 +20,23 @@
package de.tadris.fitness.location;
-import android.Manifest;
+import android.app.Notification;
+import android.app.Service;
import android.content.Context;
-import android.content.pm.PackageManager;
+import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
-
-import androidx.core.app.ActivityCompat;
+import android.os.IBinder;
+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.R;
+import de.tadris.fitness.util.NotificationHelper;
-public class LocationListener implements android.location.LocationListener {
-
- public static LatLong static_lastLocation;
+public class LocationListener extends Service {
/**
* @param location the location whose geographical coordinates should be converted.
@@ -45,113 +46,95 @@ public class LocationListener implements android.location.LocationListener {
return new LatLong(location.getLatitude(), location.getLongitude());
}
- private Context activity;
- private Location lastLocation;
- private final LocationManager locationManager;
- private boolean myLocationEnabled;
+ private static final String TAG = "LocationListener";
+ private LocationManager mLocationManager = null;
+ private static final int LOCATION_INTERVAL = 1000;
- public LocationListener(Context context) {
- super();
- this.activity= context;
- this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
- }
+ private class LocationChangedListener implements android.location.LocationListener {
+ Location mLastLocation;
-
- /**
- * 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 LocationChangedListener(String provider) {
+ Log.i(TAG, "LocationListener " + provider);
+ mLastLocation = new Location(provider);
}
- }
- 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){
+ @Override
+ public void onLocationChanged(Location location) {
+ Log.i(TAG, "onLocationChanged: " + location);
+ mLastLocation.set(location);
+ for(LocationChangeListener listener : Instance.getInstance(getBaseContext()).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)) {
- 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);
- }
- }
+ @Override
+ public void onProviderDisabled(String provider) {
+ Log.i(TAG, "onProviderDisabled: " + provider);
}
- this.myLocationEnabled = result;
- }
- private List locationChangeListeners= new ArrayList<>();
-
- public void registerLocationChangeListeners(LocationChangeListener listener){
- if(locationChangeListeners.size() == 0){
- enableMyLocation();
+ @Override
+ public void onProviderEnabled(String provider) {
+ Log.i(TAG, "onProviderEnabled: " + provider);
+ }
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ Log.i(TAG, "onStatusChanged: " + provider);
}
- locationChangeListeners.add(listener);
}
- public void unregisterLocationChangeListeners(LocationChangeListener listener){
- locationChangeListeners.remove(listener);
- if(locationChangeListeners.size() == 0){
- disableMyLocation();
+ LocationChangedListener gpsListener= new LocationChangedListener(LocationManager.GPS_PROVIDER);
+
+ @Override
+ public IBinder onBind(Intent arg0) {
+ return null;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Log.i(TAG, "onStartCommand");
+ super.onStartCommand(intent, flags, startId);
+
+ Notification.Builder builder = new Notification.Builder(this)
+ .setContentTitle(getText(R.string.trackerRunning))
+ .setContentText(getText(R.string.trackerRunningMessage));
+ //.setSmallIcon(R.drawable.icon)
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
+ NotificationHelper.createChannels(this);
+ builder.setChannelId(NotificationHelper.CHANNEL_WORKOUT);
+ }
+
+ startForeground(10, builder.build());
+
+ return START_STICKY;
+ }
+
+ @Override
+ public void onCreate() {
+ Log.i(TAG, "onCreate");
+ initializeLocationManager();
+ try {
+ mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, LOCATION_INTERVAL, 0, gpsListener);
+ } catch (java.lang.SecurityException ex) {
+ Log.i(TAG, "fail to request location update, ignore", ex);
+ } catch (IllegalArgumentException ex) {
+ Log.d(TAG, "gps provider does not exist " + ex.getMessage());
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ Log.i(TAG, "onDestroy");
+ super.onDestroy();
+ if (mLocationManager != null) {
+ mLocationManager.removeUpdates(gpsListener);
+ }
+ }
+
+ private void initializeLocationManager() {
+ Log.i(TAG, "initializeLocationManager");
+ if (mLocationManager == null) {
+ mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
}
}
diff --git a/app/src/main/java/de/tadris/fitness/location/WorkoutRecorder.java b/app/src/main/java/de/tadris/fitness/location/WorkoutRecorder.java
index d0c0d29..f535e33 100644
--- a/app/src/main/java/de/tadris/fitness/location/WorkoutRecorder.java
+++ b/app/src/main/java/de/tadris/fitness/location/WorkoutRecorder.java
@@ -73,7 +73,7 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener
Log.i("Recorder", "Start");
workout.start= System.currentTimeMillis();
resume();
- Instance.getInstance(context).locationListener.registerLocationChangeListeners(this);
+ Instance.getInstance(context).locationChangeListeners.add(this);
startWatchdog();
}else if(state == RecordingState.PAUSED){
resume();
@@ -143,7 +143,7 @@ public class WorkoutRecorder implements LocationListener.LocationChangeListener
workout.duration= time;
workout.pauseDuration= pauseTime;
state= RecordingState.STOPPED;
- Instance.getInstance(context).locationListener.unregisterLocationChangeListeners(this);
+ Instance.getInstance(context).locationChangeListeners.remove(this);
}
public void save(){
diff --git a/app/src/main/java/de/tadris/fitness/util/NotificationHelper.java b/app/src/main/java/de/tadris/fitness/util/NotificationHelper.java
new file mode 100644
index 0000000..3900700
--- /dev/null
+++ b/app/src/main/java/de/tadris/fitness/util/NotificationHelper.java
@@ -0,0 +1,54 @@
+/*
+ * 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.util;
+
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.os.Build;
+
+import de.tadris.fitness.R;
+
+public class NotificationHelper {
+
+ public static String CHANNEL_WORKOUT= "workout";
+
+ public static void createChannels(Context context){
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ createNotificationChannel(context, CHANNEL_WORKOUT, R.string.trackingInfo, R.string.trackingInfoDescription, NotificationManager.IMPORTANCE_LOW);
+ }
+ }
+
+ private static void createNotificationChannel(Context context, String id, int nameId, int descriptionId, int importance) {
+ // Create the NotificationChannel, but only on API 26+ because
+ // the NotificationChannel class is new and not in the support library
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ CharSequence name = context.getString(nameId);
+ String description = context.getString(descriptionId);
+ NotificationChannel channel = new NotificationChannel(id, name, importance);
+ channel.setDescription(description);
+ // Register the channel with the system; you can't change the importance
+ // or other notification behaviors after this
+ NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
+ notificationManager.createNotificationChannel(channel);
+ }
+ }
+
+}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 1ad9eef..2734a6f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -42,5 +42,11 @@
Delete Workout
Do you really want to delete the workout?
+ Tracker is running
+ Your workout is being recorded
+
+ Tracking Info
+ Info about the tracker running
+
Cancel