re-worked the resume functionality

master
y20k 2018-04-09 17:07:19 +02:00
parent 8264a2b2af
commit dd13d1f462
8 changed files with 125 additions and 289 deletions

View File

@ -15,8 +15,3 @@
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# needed for osmdroid v5.6.5 if using SDK version 26 TODO remove as soom as osmdroid v5.6.6 is released
# see https://github.com/osmdroid/osmdroid/issues/633
# -dontwarn org.osmdroid.tileprovider.modules.NetworkAvailabliltyCheck

View File

@ -178,14 +178,15 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys {
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onStop() {
super.onStop();
// unbind from TrackerService
unbindService(mConnection);
mBound = false;
}
@ -269,14 +270,6 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys {
}
/* Request the current Track from TrackerService */
public void requestTrack() {
if (mBound) {
mTrackerService.sendTrackUpdate();
}
}
/* Handles the visual state after a save action */
private void handleStateAfterSave() {
// display and update tracks tab

View File

@ -225,19 +225,25 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
// load state of tracker service - see if anything changed
loadTrackerServiceState(mActivity);
// CASE 1: recording active
if (mTrackerServiceRunning) {
// request an updated track recording from service
((MainActivity)mActivity).requestTrack();
}
// CASE 2: recording stopped - temp file exists
else if (mStorageHelper.tempFileExists()) {
// load track from temp file if it exists
if (mStorageHelper.tempFileExists()) {
LoadTempTrackAsyncHelper loadTempTrackAsyncHelper = new LoadTempTrackAsyncHelper();
loadTempTrackAsyncHelper.execute();
}
// // CASE 1: recording active
// if (mTrackerServiceRunning) {
// // request an updated track recording from service
// ((MainActivity)mActivity).requestTrack();
// }
//
// // CASE 2: recording stopped - temp file exists
// else if (mStorageHelper.tempFileExists()) {
// // load track from temp file if it exists
// LoadTempTrackAsyncHelper loadTempTrackAsyncHelper = new LoadTempTrackAsyncHelper();
// loadTempTrackAsyncHelper.execute();
// }
// // CASE 3: not recording and no temp file
// else if (mTrack != null) {
// // just draw existing track data (from saved instance)
@ -551,7 +557,6 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.hasExtra(EXTRA_TRACK) && intent.hasExtra(EXTRA_LAST_LOCATION)) {
LogHelper.v(LOG_TAG, "Track update received.");
// draw track on map
mTrack = intent.getParcelableExtra(EXTRA_TRACK);
drawTrackOverlay(mTrack);

View File

@ -37,7 +37,6 @@ import android.os.CountDownTimer;
import android.os.Handler;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.widget.Toast;
@ -51,7 +50,6 @@ import org.y20k.trackbook.helpers.StorageHelper;
import org.y20k.trackbook.helpers.TrackbookKeys;
import java.util.List;
import java.util.Random;
import static android.hardware.Sensor.TYPE_STEP_COUNTER;
@ -115,17 +113,14 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
@Override
public boolean onUnbind(Intent intent) {
// All clients have unbound with unbindService()
// return mAllowRebind; // todo change
// return true if you would like to have the service's onRebind(Intent) method later called when new clients bind to it.
return true;
}
@Override
public void onRebind(Intent intent) {
// A client is binding to the service with bindService(),
// after onUnbind() has already been called
// a client is binding to the service with bindService(), after onUnbind() has already been called
}
@ -141,68 +136,11 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
resumeTracking();
}
// // check if user did turn off location in device settings
// if (!mLocationSystemSetting) {
// LogHelper.i(LOG_TAG, "Location Setting is turned off.");
// Toast.makeText(getApplicationContext(), R.string.toast_message_location_offline, Toast.LENGTH_LONG).show();
// stopTracking();
// return START_STICKY;
// }
//
// // RESTART CHECK: checking for empty intent - try to get saved track
// if (intent == null || intent.getAction() == null) {
// LogHelper.w(LOG_TAG, "Null-Intent received. Trying to restart tracking.");
// startTracking(intent, false);
// }
//
// // ACTION START
// else if (intent.getAction().equals(ACTION_START) && mLocationSystemSetting) {
// startTracking(intent, true);
// }
//
// // ACTION RESUME
// else if (intent.getAction().equals(ACTION_RESUME) && mLocationSystemSetting) {
// startTracking(intent, false);
// }
//
// // ACTION STOP
// else if (intent.getAction().equals(ACTION_STOP) || !mLocationSystemSetting) {
// mTrackerServiceRunning = false;
// if (mTrack != null && mTimer != null) {
// stopTracking();
// } else {
// // handle error - save state
// saveTrackerServiceState(mTrackerServiceRunning, FAB_STATE_DEFAULT);
// }
// }
//
// // ACTION DISMISS
// else if (intent.getAction().equals(ACTION_DISMISS)) {
// // save state
// saveTrackerServiceState(mTrackerServiceRunning, FAB_STATE_DEFAULT);
// // dismiss notification
// mNotificationManager.cancel(TRACKER_SERVICE_NOTIFICATION_ID); // todo check if necessary?
// stopForeground(true);
// }
//
// // ACTION TRACK REQUEST
// else if (intent.getAction().equals(ACTION_TRACK_REQUEST)) {
// // send track via broadcast
// sendTrackUpdate();
// }
// START_STICKY is used for services that are explicitly started and stopped as needed
return START_STICKY;
}
// @Nullable
// @Override
// public IBinder onBind(Intent intent) {
// return null;
// }
@Override
public void onDestroy() {
LogHelper.v(LOG_TAG, "onDestroy called.");
@ -258,7 +196,7 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
mStepCountOffset = 0;
// begin recording
recordMovements();
startMovementRecording();
} else {
LogHelper.i(LOG_TAG, "Location Setting is turned off.");
@ -299,7 +237,7 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
mStepCountOffset = mTrack.getStepCount();
// begin recording
recordMovements();
startMovementRecording();
} else {
LogHelper.i(LOG_TAG, "Location Setting is turned off.");
@ -308,185 +246,17 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
}
/* Record movements */
private void recordMovements() {
// add last location as WayPoint to track
addWayPointToTrack();
// put up notification
displayNotification(true);
// create gps and network location listeners
startFindingLocation();
// start timer that periodically request a location update
startIntervalTimer();
// start counting steps
startStepCounter();
// register content observer for changes in System Settings
this.getContentResolver().registerContentObserver(android.provider.Settings.Secure.CONTENT_URI, true, mSettingsContentObserver);
// start service in foreground
startForeground(TRACKER_SERVICE_NOTIFICATION_ID, mNotification);
}
private void startStepCounter() {
boolean stepCounterAvailable;
stepCounterAvailable = mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(TYPE_STEP_COUNTER), SensorManager.SENSOR_DELAY_UI);
if (stepCounterAvailable) {
LogHelper.v(LOG_TAG, "Pedometer sensor available: Registering listener.");
} else {
LogHelper.i(LOG_TAG, "Pedometer sensor not available.");
mTrack.setStepCount(-1);
}
}
/* Set timer to retrieve new locations and to prevent endless tracking */
private void startIntervalTimer() {
mTimer = new CountDownTimer(EIGHT_HOURS_IN_MILLISECONDS, FIFTEEN_SECONDS_IN_MILLISECONDS) {
@Override
public void onTick(long millisUntilFinished) {
// update track duration - and add duration from previously interrupted / paused session
long previouslyRecordedDuration = mTrack.getTrackDuration();
long duration = EIGHT_HOURS_IN_MILLISECONDS - millisUntilFinished + previouslyRecordedDuration;
mTrack.setDuration(duration);
// try to add WayPoint to Track
addWayPointToTrack();
// update notification
mNotification = NotificationHelper.getUpdatedNotification(TrackerService.this, mNotificationBuilder, mTrack);
mNotificationManager.notify(TRACKER_SERVICE_NOTIFICATION_ID, mNotification);
// save a temp file in case the service has been killed by the system
SaveTempTrackAsyncHelper saveTempTrackAsyncHelper = new SaveTempTrackAsyncHelper();
saveTempTrackAsyncHelper.execute();
}
@Override
public void onFinish() {
// stop tracking after eight hours
stopTracking();
}
};
mTimer.start();
}
/* Display notification */
private void displayNotification(boolean trackingState) {
mNotificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANEL_ID_RECORDING_CHANNEL);
mNotification = NotificationHelper.getNotification(this, mNotificationBuilder, mTrack, trackingState);
mNotificationManager.notify(TRACKER_SERVICE_NOTIFICATION_ID, mNotification); // todo check if necessary in pre Android O
}
/* Start tracking location */ // todo remove
private void startTracking(@Nullable Intent intent, boolean createNewTrack) {
LogHelper.v(LOG_TAG, "Service received command: START");
// create a new track - if requested
if (createNewTrack) {
mTrack = new Track();
} else {
StorageHelper storageHelper = new StorageHelper(this);
if (storageHelper.tempFileExists()) {
// load temp track file
mTrack = storageHelper.loadTrack(FILE_TEMP_TRACK);
// try to mark last waypoint as stopover
int lastWayPoint = mTrack.getWayPoints().size() - 1;
if (lastWayPoint >= 0) {
mTrack.getWayPoints().get(lastWayPoint).setIsStopOver(true);
}
} else {
// fallback, if tempfile did not exist
LogHelper.e(LOG_TAG, "Unable to find previously saved track temp file.");
mTrack = new Track();
}
}
// get last location
if (intent != null && ACTION_START.equals(intent.getAction()) && intent.hasExtra(EXTRA_LAST_LOCATION)) {
// received START intent and last location - unpack last location
mCurrentBestLocation = intent.getParcelableExtra(EXTRA_LAST_LOCATION);
} else if (ACTION_RESUME.equals(intent.getAction()) && mTrack.getSize() > 0) {
// received RESUME intent - use last waypoint
mCurrentBestLocation = mTrack.getWayPointLocation(mTrack.getSize() -1);
}
// get last location - fallback
if (mCurrentBestLocation == null) {
mCurrentBestLocation = LocationHelper.determineLastKnownLocation(mLocationManager);
}
// add last location as WayPoint to track
addWayPointToTrack();
// put up notification
mNotificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANEL_ID_RECORDING_CHANNEL);
mNotification = NotificationHelper.getNotification(this, mNotificationBuilder, mTrack, true);
mNotificationManager.notify(TRACKER_SERVICE_NOTIFICATION_ID, mNotification); // todo check if necessary in pre Android O
// get duration of previously recorded track - in case this service has been restarted / resumed
final long previouslyRecordedDuration = mTrack.getTrackDuration();
// set timer to retrieve new locations and to prevent endless tracking
mTimer = new CountDownTimer(EIGHT_HOURS_IN_MILLISECONDS, FIFTEEN_SECONDS_IN_MILLISECONDS) {
@Override
public void onTick(long millisUntilFinished) {
// update track duration - and add duration from previously interrupted / paused session
long duration = EIGHT_HOURS_IN_MILLISECONDS - millisUntilFinished + previouslyRecordedDuration;
mTrack.setDuration(duration);
// try to add WayPoint to Track
addWayPointToTrack();
// update notification
mNotification = NotificationHelper.getUpdatedNotification(TrackerService.this, mNotificationBuilder, mTrack);
mNotificationManager.notify(TRACKER_SERVICE_NOTIFICATION_ID, mNotification);
// save a temp file in case the service has been killed by the system
SaveTempTrackAsyncHelper saveTempTrackAsyncHelper = new SaveTempTrackAsyncHelper();
saveTempTrackAsyncHelper.execute();
}
@Override
public void onFinish() {
// stop tracking after eight hours
stopTracking();
}
};
mTimer.start();
// initialize step counter
mStepCountOffset = 0;
boolean stepCounterAvailable;
stepCounterAvailable = mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(TYPE_STEP_COUNTER), SensorManager.SENSOR_DELAY_UI);
if (stepCounterAvailable) {
LogHelper.v(LOG_TAG, "Pedometer sensor available: Registering listener.");
} else {
LogHelper.i(LOG_TAG, "Pedometer sensor not available.");
mTrack.setStepCount(-1);
}
// create gps and network location listeners
startFindingLocation();
// register content observer for changes in System Settings
this.getContentResolver().registerContentObserver(android.provider.Settings.Secure.CONTENT_URI, true, mSettingsContentObserver);
// start service in foreground
startForeground(TRACKER_SERVICE_NOTIFICATION_ID, mNotification);
}
/* Stop tracking location */
public void stopTracking() {
LogHelper.v(LOG_TAG, "Recording stopped");
// catches a bug that leaves the ui in a incorrect state after a crash
if (!mTrackerServiceRunning) {
saveTrackerServiceState(mTrackerServiceRunning, FAB_STATE_SAVE);
broadcastTrackingStateChange();
return;
}
// store current date and time
mTrack.setRecordingEnd();
@ -494,7 +264,7 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
mTimer.cancel();
// broadcast an updated track
sendTrackUpdate();
broadcastTrackUpdate();
// save a temp file in case the activity has been killed
SaveTempTrackAsyncHelper saveTempTrackAsyncHelper = new SaveTempTrackAsyncHelper();
@ -525,6 +295,80 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
}
/* Starts to record movements */
private void startMovementRecording() {
// add last location as WayPoint to track
addWayPointToTrack();
// put up notification
displayNotification(true);
// create gps and network location listeners
startFindingLocation();
// start timer that periodically request a location update
startRequestingLocationChanges();
// start counting steps
startStepCounter();
// register content observer for changes in System Settings
this.getContentResolver().registerContentObserver(android.provider.Settings.Secure.CONTENT_URI, true, mSettingsContentObserver);
// start service in foreground
startForeground(TRACKER_SERVICE_NOTIFICATION_ID, mNotification);
}
/* Registers a step counter listener */
private void startStepCounter() {
boolean stepCounterAvailable;
stepCounterAvailable = mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(TYPE_STEP_COUNTER), SensorManager.SENSOR_DELAY_UI);
if (stepCounterAvailable) {
LogHelper.v(LOG_TAG, "Pedometer sensor available: Registering listener.");
} else {
LogHelper.i(LOG_TAG, "Pedometer sensor not available.");
mTrack.setStepCount(-1);
}
}
/* Set timer to periodically retrieve new locations and to prevent endless tracking */
private void startRequestingLocationChanges() {
final long previouslyRecordedDuration = mTrack.getTrackDuration();
mTimer = new CountDownTimer(EIGHT_HOURS_IN_MILLISECONDS, FIFTEEN_SECONDS_IN_MILLISECONDS) {
@Override
public void onTick(long millisUntilFinished) {
// update track duration - and add duration from previously interrupted / paused session
long duration = EIGHT_HOURS_IN_MILLISECONDS - millisUntilFinished + previouslyRecordedDuration;
mTrack.setDuration(duration);
// try to add WayPoint to Track
addWayPointToTrack();
// update notification
mNotification = NotificationHelper.getUpdatedNotification(TrackerService.this, mNotificationBuilder, mTrack);
mNotificationManager.notify(TRACKER_SERVICE_NOTIFICATION_ID, mNotification);
// save a temp file in case the service has been killed by the system
SaveTempTrackAsyncHelper saveTempTrackAsyncHelper = new SaveTempTrackAsyncHelper();
saveTempTrackAsyncHelper.execute();
}
@Override
public void onFinish() {
// stop tracking after eight hours
stopTracking();
}
};
mTimer.start();
}
/* Display notification */
private void displayNotification(boolean trackingState) {
mNotificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANEL_ID_RECORDING_CHANNEL);
mNotification = NotificationHelper.getNotification(this, mNotificationBuilder, mTrack, trackingState);
mNotificationManager.notify(TRACKER_SERVICE_NOTIFICATION_ID, mNotification); // todo check if necessary in pre Android O
}
/* Adds a new WayPoint to current track */
private void addWayPointToTrack() {
@ -550,7 +394,7 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
Location firstWayPoint = mTrack.getWayPointLocation(0);
float distance = firstWayPoint.distanceTo(lastWayPoint);
long timeDifference = lastWayPoint.getElapsedRealtimeNanos() - firstWayPoint.getElapsedRealtimeNanos();
averageSpeed = distance / ((float) timeDifference / ONE_NANOSECOND);
averageSpeed = distance / ((float) timeDifference / ONE_SECOND_IN_NANOSECOND);
}
if (LocationHelper.isNewWayPoint(lastWayPoint, mCurrentBestLocation, averageSpeed)) {
@ -561,14 +405,14 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
// send local broadcast if new WayPoint added
if (newWayPoint != null) {
sendTrackUpdate();
broadcastTrackUpdate();
}
}
/* Broadcasts a track update */
public void sendTrackUpdate() {
private void broadcastTrackUpdate() {
if (mTrack != null) {
Intent i = new Intent();
i.setAction(ACTION_TRACK_UPDATED);

View File

@ -143,7 +143,7 @@ public final class LocationHelper implements TrackbookKeys {
if (newLocation.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
// calculate speed difference
float speedDifference;
float currentSpeed = distance / ((float)timeDifference / ONE_NANOSECOND);
float currentSpeed = distance / ((float)timeDifference / ONE_SECOND_IN_NANOSECOND);
if (currentSpeed > averageSpeed) {
speedDifference = currentSpeed / averageSpeed;
} else {
@ -163,11 +163,11 @@ public final class LocationHelper implements TrackbookKeys {
}
// DEFAULT network: distance is bigger than 30 meters and time difference bigger than 12 seconds
return distance > 30 && timeDifference >= 12 * ONE_NANOSECOND; // TODO add minimal accuracy
return distance > 30 && timeDifference >= 12 * ONE_SECOND_IN_NANOSECOND; // TODO add minimal accuracy
} else {
// DEFAULT GPS: distance is bigger than 10 meters and time difference bigger than 12 seconds
return distance > 10 && timeDifference >= 12 * ONE_NANOSECOND;
return distance > 10 && timeDifference >= 12 * ONE_SECOND_IN_NANOSECOND;
}
}

View File

@ -51,9 +51,6 @@ public final class NotificationHelper implements TrackbookKeys {
// create notification channel
createNotificationChannel(context);
// build context text for notification builder
String contentText = getContextString(context, track);
// ACTION: NOTIFICATION TAP & BUTTON SHOW
Intent tapActionIntent = new Intent(context, MainActivity.class);
tapActionIntent.setAction(ACTION_SHOW_MAP);

View File

@ -17,6 +17,7 @@
package org.y20k.trackbook.helpers;
import android.content.Context;
import android.location.Location;
import android.os.Environment;
import android.support.annotation.Nullable;
import android.support.v4.os.EnvironmentCompat;
@ -369,8 +370,8 @@ public class StorageHelper implements TrackbookKeys {
double negativeElevation = 0;
if (track != null && track.getWayPoints().size() > 0) {
double previousLocationHeight;
double currentLocationHeight;
double previousLocationAltitude;
double currentLocationAltitude;
long previousTimeStamp;
long currentTimeStamp;
@ -379,7 +380,7 @@ public class StorageHelper implements TrackbookKeys {
minAltitude = maxAltitude;
// apply filter & smooth data
// track = lowPass(track, 15f, 35f);
// track = smoothTrack(track, 15f, 35f);
// iterate over track
for (int i = 1; i < track.getWayPoints().size(); i++ ) {
@ -393,23 +394,23 @@ public class StorageHelper implements TrackbookKeys {
double timeDiffFactor = timeDiff / FIFTEEN_SECONDS_IN_MILLISECONDS;
// height of previous and current waypoints
previousLocationHeight = track.getWayPointLocation(i -1).getAltitude();
currentLocationHeight = track.getWayPointLocation(i).getAltitude();
previousLocationAltitude = track.getWayPointLocation(i -1).getAltitude();
currentLocationAltitude = track.getWayPointLocation(i).getAltitude();
// check for new min and max heights
if (currentLocationHeight > maxAltitude) {
maxAltitude = currentLocationHeight;
if (currentLocationAltitude > maxAltitude) {
maxAltitude = currentLocationAltitude;
}
if (minAltitude == 0 || currentLocationHeight < minAltitude) {
minAltitude = currentLocationHeight;
if (minAltitude == 0 || currentLocationAltitude < minAltitude) {
minAltitude = currentLocationAltitude;
}
// get elevation difference and sum it up
double altitudeDiff = currentLocationHeight - previousLocationHeight;
if (altitudeDiff > 0 && altitudeDiff < MEASUREMENT_ERROR_THRESHOLD * timeDiffFactor && currentLocationHeight != 0) {
double altitudeDiff = currentLocationAltitude - previousLocationAltitude;
if (altitudeDiff > 0 && altitudeDiff < MEASUREMENT_ERROR_THRESHOLD * timeDiffFactor && currentLocationAltitude != 0) {
positiveElevation = positiveElevation + altitudeDiff;
}
if (altitudeDiff < 0 && altitudeDiff > -MEASUREMENT_ERROR_THRESHOLD * timeDiffFactor && currentLocationHeight != 0) {
if (altitudeDiff < 0 && altitudeDiff > -MEASUREMENT_ERROR_THRESHOLD * timeDiffFactor && currentLocationAltitude != 0) {
negativeElevation = negativeElevation + altitudeDiff;
}
@ -424,8 +425,9 @@ public class StorageHelper implements TrackbookKeys {
return track;
}
/* Tries to smooth the elevation data using a low pass filter */
private Track lowPass(Track input, float dt, float rc) {
private Track smoothTrack(Track input, float dt, float rc) {
// The following code is adapted from https://en.wikipedia.org/wiki/Low-pass_filter
//

View File

@ -86,7 +86,7 @@ public interface TrackbookKeys {
int RESULT_EXPORT_DIALOG = 4;
/* CONSTANTS */
long ONE_NANOSECOND = 1000000000L;
long ONE_SECOND_IN_NANOSECOND = 1000000000L;
long EIGHT_HOURS_IN_MILLISECONDS = 43200000; // maximum tracking duration
long FIFTEEN_SECONDS_IN_MILLISECONDS = 15000; // timer interval for tracking
long FIVE_MINUTES_IN_NANOSECONDS = 5L * 60000000000L; // determines a stop over