Trackbook should now (more or less) gracefully handle changes to the Location setting in System Settings (#3).

master
y20k 2016-09-19 18:46:25 +02:00
parent 81b8219b93
commit 3256d97bb6
8 changed files with 315 additions and 117 deletions

View File

@ -43,16 +43,19 @@ To stop your recording press the big blue button again or use the stop button in
### Distance and duration ### Distance and duration
Peek into Trackbook's notification to see the distance and duration of your current recording. Peek into Trackbook's notification to see the distance and duration of your current recording.
### How do you measure the distance?
Trackbook calculates the distance between markers and adds them up.
### Clear the map ### Clear the map
You can clear the map by either long-pressing the big blue button or dismissing the notification. You can clear the map by either long-pressing the big blue button or dismissing the notification.
Which Permissions does Trackbook need? Which Permissions does Trackbook need?
-------------------------------------- --------------------------------------
### Permission "INTERNET" ### Permission "INTERNET"
Trackbook needs to download map data from Open Street Map servers and therefore needs access to the internet. Trackbook needs to download map data from OpenStreetMap servers and therefore needs access to the internet.
### Permission "ACCESS_NETWORK_STATE" and "ACCESS_WIFI_STATE" ### Permission "ACCESS_NETWORK_STATE" and "ACCESS_WIFI_STATE"
Trackbook uses [osmdroid](https://github.com/osmdroid/osmdroid/) to draw its main map. osmdroid needs to know the current state of your devices connectivity - see [Prerequisites](https://github.com/osmdroid/osmdroid/wiki/Prerequisites). I am not sure why though. On the other hand: These permissions are not harmful in any way. Trackbook uses [osmdroid](https://github.com/osmdroid/osmdroid/) to draw its maps. osmdroid needs to know the current state of your devices connectivity - see [Prerequisites](https://github.com/osmdroid/osmdroid/wiki/Prerequisites).
### Permission "ACCESS_COARSE_LOCATION" and "ACCESS_FINE_LOCATION" ### Permission "ACCESS_COARSE_LOCATION" and "ACCESS_FINE_LOCATION"
Trackbook needs accurate GPS location data to be able to record your movements. If the GPS data is not available or not accurate enough Trackbook uses location data from cell tower and WiFi triangulation. Trackbook needs accurate GPS location data to be able to record your movements. If the GPS data is not available or not accurate enough Trackbook uses location data from cell tower and WiFi triangulation.

View File

@ -22,12 +22,15 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.location.Location; import android.location.Location;
import android.location.LocationListener; import android.location.LocationListener;
import android.location.LocationManager; import android.location.LocationManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock; import android.os.SystemClock;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -65,7 +68,9 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
private Activity mActivity; private Activity mActivity;
private Track mTrack; private Track mTrack;
private boolean mFirstStart; private boolean mFirstStart;
private Snackbar mLocationOffBar;
private BroadcastReceiver mTrackUpdatedReceiver; private BroadcastReceiver mTrackUpdatedReceiver;
private SettingsContentObserver mSettingsContentObserver;
private MapView mMapView; private MapView mMapView;
private IMapController mController; private IMapController mController;
private LocationManager mLocationManager; private LocationManager mLocationManager;
@ -76,6 +81,7 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
private Location mCurrentBestLocation; private Location mCurrentBestLocation;
private boolean mTrackerServiceRunning; private boolean mTrackerServiceRunning;
private boolean mLocalTrackerRunning; private boolean mLocalTrackerRunning;
private boolean mLocationSystemSetting;
private boolean mFragmentVisible; private boolean mFragmentVisible;
@ -109,12 +115,6 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
// acquire reference to Location Manager // acquire reference to Location Manager
mLocationManager = (LocationManager) mActivity.getSystemService(Context.LOCATION_SERVICE); mLocationManager = (LocationManager) mActivity.getSystemService(Context.LOCATION_SERVICE);
// check if location services are available
if (mLocationManager.getProviders(true).size() == 0) {
// ask user to turn on location services
promptUserForLocation();
}
// CASE 1: get saved location if possible // CASE 1: get saved location if possible
if (savedInstanceState != null) { if (savedInstanceState != null) {
Location savedLocation = savedInstanceState.getParcelable(INSTANCE_CURRENT_LOCATION); Location savedLocation = savedInstanceState.getParcelable(INSTANCE_CURRENT_LOCATION);
@ -131,11 +131,23 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
mCurrentBestLocation = LocationHelper.determineLastKnownLocation(mLocationManager); mCurrentBestLocation = LocationHelper.determineLastKnownLocation(mLocationManager);
} }
// CASE 3: location services are available but unable to get location - this should not happen
if (mCurrentBestLocation == null) {
mCurrentBestLocation = new Location(LocationManager.NETWORK_PROVIDER);
mCurrentBestLocation.setLatitude(DEFAULT_LATITUDE);
mCurrentBestLocation.setLongitude(DEFAULT_LONGITUDE);
}
// get state of location system setting
mLocationSystemSetting = LocationHelper.checkLocationSystemSetting(mActivity);
// create content observer for changes in System Settings
mSettingsContentObserver = new SettingsContentObserver( new Handler());
// register broadcast receiver for new WayPoints // register broadcast receiver for new WayPoints
mTrackUpdatedReceiver = createTrackUpdatedReceiver(); mTrackUpdatedReceiver = createTrackUpdatedReceiver();
IntentFilter trackUpdatedIntentFilter = new IntentFilter(ACTION_TRACK_UPDATED); IntentFilter trackUpdatedIntentFilter = new IntentFilter(ACTION_TRACK_UPDATED);
LocalBroadcastManager.getInstance(mActivity).registerReceiver(mTrackUpdatedReceiver, trackUpdatedIntentFilter); LocalBroadcastManager.getInstance(mActivity).registerReceiver(mTrackUpdatedReceiver, trackUpdatedIntentFilter);
} }
@ -157,7 +169,7 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
// initiate map state // initiate map state
if (savedInstanceState != null) { if (savedInstanceState != null) {
// restore saved instance of map // restore saved instance of map
GeoPoint position = new GeoPoint(savedInstanceState.getDouble(INSTANCE_LATITUDE), savedInstanceState.getDouble(INSTANCE_LONGITUDE)); GeoPoint position = new GeoPoint(savedInstanceState.getDouble(INSTANCE_LATITUDE, DEFAULT_LATITUDE), savedInstanceState.getDouble(INSTANCE_LONGITUDE, DEFAULT_LONGITUDE));
mController.setCenter(position); mController.setCenter(position);
mController.setZoom(savedInstanceState.getInt(INSTANCE_ZOOM_LEVEL, 16)); mController.setZoom(savedInstanceState.getInt(INSTANCE_ZOOM_LEVEL, 16));
// restore current location // restore current location
@ -198,7 +210,6 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
} }
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
@ -206,11 +217,6 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
// set visibility // set visibility
mFragmentVisible = true; mFragmentVisible = true;
// start preliminary tracking - if no TrackerService is running
if (!mTrackerServiceRunning && mFragmentVisible) {
startPreliminaryTracking();
}
// center map on current position - if TrackerService is running // center map on current position - if TrackerService is running
if (mTrackerServiceRunning) { if (mTrackerServiceRunning) {
mController.setCenter(convertToGeoPoint(mCurrentBestLocation)); mController.setCenter(convertToGeoPoint(mCurrentBestLocation));
@ -221,6 +227,16 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
drawTrackOverlay(mTrack); drawTrackOverlay(mTrack);
} }
// show/hide the location off notification bar
toggleLocationOffBar();
// start preliminary tracking - if no TrackerService is running
if (!mTrackerServiceRunning && mFragmentVisible) {
startPreliminaryTracking();
}
// register content observer for changes in System Settings
mActivity.getContentResolver().registerContentObserver(android.provider.Settings.Secure.CONTENT_URI, true, mSettingsContentObserver );
} }
@ -233,6 +249,9 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
// disable preliminary location listeners // disable preliminary location listeners
stopPreliminaryTracking(); stopPreliminaryTracking();
// disable content observer for changes in System Settings
mActivity.getContentResolver().unregisterContentObserver(mSettingsContentObserver);
} }
@ -268,11 +287,10 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
// CASE MY LOCATION // CASE MY LOCATION
case R.id.action_bar_my_location: case R.id.action_bar_my_location:
// do nothing if location setting is off
if (mLocationManager.getProviders(true).size() == 0) { if (toggleLocationOffBar()) {
// location services are off - ask user to turn them on stopPreliminaryTracking();
promptUserForLocation(); return false;
return true;
} }
// get current position // get current position
@ -310,7 +328,6 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
@Override @Override
public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(Bundle outState) {
// save map position
outState.putBoolean(INSTANCE_FIRST_START, mFirstStart); outState.putBoolean(INSTANCE_FIRST_START, mFirstStart);
outState.putDouble(INSTANCE_LATITUDE, mMapView.getMapCenter().getLatitude()); outState.putDouble(INSTANCE_LATITUDE, mMapView.getMapCenter().getLatitude());
outState.putDouble(INSTANCE_LONGITUDE, mMapView.getMapCenter().getLongitude()); outState.putDouble(INSTANCE_LONGITUDE, mMapView.getMapCenter().getLongitude());
@ -366,26 +383,32 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
/* Start preliminary tracking for map */ /* Start preliminary tracking for map */
private void startPreliminaryTracking() { private void startPreliminaryTracking() {
mLocalTrackerRunning = true; if (mLocationSystemSetting && !mLocalTrackerRunning) {
// create location listeners // create location listeners
List locationProviders = mLocationManager.getProviders(true); List locationProviders = mLocationManager.getAllProviders();
if (locationProviders.contains(LocationManager.GPS_PROVIDER)) { if (locationProviders.contains(LocationManager.GPS_PROVIDER)) {
mGPSListener = createLocationListener(); mGPSListener = createLocationListener();
mLocalTrackerRunning = true;
} }
if (locationProviders.contains(LocationManager.NETWORK_PROVIDER)) { if (locationProviders.contains(LocationManager.NETWORK_PROVIDER)) {
mNetworkListener = createLocationListener(); mNetworkListener = createLocationListener();
mLocalTrackerRunning = true;
} }
// register listeners // register listeners
LocationHelper.registerLocationListeners(mLocationManager, mGPSListener, mNetworkListener); LocationHelper.registerLocationListeners(mLocationManager, mGPSListener, mNetworkListener);
LogHelper.v(LOG_TAG, "Starting preliminary tracking.");
}
} }
/* Removes gps and network location listeners */ /* Removes gps and network location listeners */
private void stopPreliminaryTracking() { private void stopPreliminaryTracking() {
if (mLocalTrackerRunning) {
mLocalTrackerRunning = false; mLocalTrackerRunning = false;
// remove listeners // remove listeners
LocationHelper.removeLocationListeners(mLocationManager, mGPSListener, mNetworkListener); LocationHelper.removeLocationListeners(mLocationManager, mGPSListener, mNetworkListener);
LogHelper.v(LOG_TAG, "Stopping preliminary tracking.");
}
} }
@ -403,7 +426,7 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
} }
public void onStatusChanged(String provider, int status, Bundle extras) { public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO do something LogHelper.v(LOG_TAG, "Location provider status change: " + provider + " | " + status);
} }
public void onProviderEnabled(String provider) { public void onProviderEnabled(String provider) {
@ -436,10 +459,28 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
} }
/* Prompts user to turn on location */ /* Toggles snackbar indicating that location setting is off */
private void promptUserForLocation() { private boolean toggleLocationOffBar() {
// TODO prompt user to turn on location // create snackbar indicator for location setting off
Toast.makeText(mActivity, mActivity.getString(R.string.toast_message_location_offline), Toast.LENGTH_LONG).show(); if (mLocationOffBar == null) {
mLocationOffBar = Snackbar.make(mMapView, R.string.snackbar_message_location_offline, Snackbar.LENGTH_INDEFINITE).setAction("Action", null);
}
// get state of location system setting
mLocationSystemSetting = LocationHelper.checkLocationSystemSetting(mActivity);
// show snackbar if necessary
if (!mLocationSystemSetting) {
// show snackbar
mLocationOffBar.show();
return true;
} else {
// hide snackbar
mLocationOffBar.dismiss();
return false;
}
} }
@ -465,7 +506,11 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
/* Converts Location to GeoPoint */ /* Converts Location to GeoPoint */
private GeoPoint convertToGeoPoint (Location location) { private GeoPoint convertToGeoPoint (Location location) {
if (location != null) {
return new GeoPoint(location.getLatitude(), location.getLongitude()); return new GeoPoint(location.getLatitude(), location.getLongitude());
} else {
return new GeoPoint(DEFAULT_LATITUDE, DEFAULT_LONGITUDE);
}
} }
@ -484,4 +529,43 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys {
int zoom = settings.getInt(PREFS_ZOOM_LEVEL, 16); int zoom = settings.getInt(PREFS_ZOOM_LEVEL, 16);
} }
/**
* Inner class: SettingsContentObserver is a custom ContentObserver for changes in Android Settings
*/
public class SettingsContentObserver extends ContentObserver {
public SettingsContentObserver(Handler handler) {
super(handler);
}
@Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
LogHelper.v(LOG_TAG, "System Setting change detected.");
// check if location setting was changed
boolean previousLocationSystemSetting = mLocationSystemSetting;
mLocationSystemSetting = LocationHelper.checkLocationSystemSetting(mActivity);
if (previousLocationSystemSetting != mLocationSystemSetting) {
LogHelper.v(LOG_TAG, "Location Setting change detected.");
toggleLocationOffBar();
}
// start / stop perliminary tracking
if (!mLocationSystemSetting) {
stopPreliminaryTracking();
} else if (!mTrackerServiceRunning && mFragmentVisible) {
startPreliminaryTracking();
}
}
}
} }

View File

@ -19,6 +19,7 @@ package org.y20k.trackbook;
import android.app.Service; import android.app.Service;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.database.ContentObserver;
import android.hardware.Sensor; import android.hardware.Sensor;
import android.hardware.SensorEvent; import android.hardware.SensorEvent;
import android.hardware.SensorEventListener; import android.hardware.SensorEventListener;
@ -28,9 +29,11 @@ import android.location.LocationListener;
import android.location.LocationManager; import android.location.LocationManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.CountDownTimer; import android.os.CountDownTimer;
import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import android.widget.Toast;
import org.y20k.trackbook.core.Track; import org.y20k.trackbook.core.Track;
import org.y20k.trackbook.core.WayPoint; import org.y20k.trackbook.core.WayPoint;
@ -39,6 +42,7 @@ import org.y20k.trackbook.helpers.LogHelper;
import org.y20k.trackbook.helpers.NotificationHelper; import org.y20k.trackbook.helpers.NotificationHelper;
import org.y20k.trackbook.helpers.TrackbookKeys; import org.y20k.trackbook.helpers.TrackbookKeys;
import java.util.GregorianCalendar;
import java.util.List; import java.util.List;
@ -59,7 +63,10 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
private float mStepCountOffset; private float mStepCountOffset;
private LocationListener mGPSListener = null; private LocationListener mGPSListener = null;
private LocationListener mNetworkListener = null; private LocationListener mNetworkListener = null;
private SettingsContentObserver mSettingsContentObserver;
private Location mCurrentBestLocation; private Location mCurrentBestLocation;
private boolean mTrackerServiceRunning;
private boolean mLocationSystemSetting;
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
@ -70,14 +77,86 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
// acquire reference to Sensor Manager // acquire reference to Sensor Manager
mSensorManager = (SensorManager) this.getSystemService(Context.SENSOR_SERVICE); mSensorManager = (SensorManager) this.getSystemService(Context.SENSOR_SERVICE);
// get state of location system setting
mLocationSystemSetting = LocationHelper.checkLocationSystemSetting(getApplicationContext());
// create content observer for changes in System Settings
mSettingsContentObserver = new SettingsContentObserver( new Handler());
// checking for empty intent // checking for empty intent
if (intent == null) { if (intent == null) {
LogHelper.v(LOG_TAG, "Null-Intent received. Stopping self."); LogHelper.v(LOG_TAG, "Null-Intent received. Stopping self.");
stopSelf(); stopSelf();
} }
// check if user did turn off location in device settings
if (!mLocationSystemSetting) {
LogHelper.v(LOG_TAG, "Location Setting is turned off.");
Toast.makeText(getApplicationContext(), R.string.toast_message_location_offline, Toast.LENGTH_LONG).show();
stopTracking();
return START_STICKY;
}
// ACTION START // ACTION START
else if (intent.getAction().equals(ACTION_START)) { else if (intent.getAction().equals(ACTION_START) && mLocationSystemSetting) {
startTracking(intent);
}
// ACTION STOP
else if (intent.getAction().equals(ACTION_STOP) || !mLocationSystemSetting) {
stopTracking();
}
// 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.");
// remove listeners
stopFindingLocation();
mSensorManager.unregisterListener(this);
// cancel notification
stopForeground(true);
super.onDestroy();
}
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
// save the step count offset / previously recorded steps
if (mStepCountOffset == 0) {
mStepCountOffset = sensorEvent.values[0] - 1;
}
// calculate step count
float stepCount = sensorEvent.values[0] - mStepCountOffset;
// set step count in track
mTrack.setStepCount(stepCount);
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
private void startTracking(Intent intent) {
LogHelper.v(LOG_TAG, "Service received command: START"); LogHelper.v(LOG_TAG, "Service received command: START");
// create a new track // create a new track
@ -131,12 +210,17 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
// create gps and network location listeners // create gps and network location listeners
startFindingLocation(); startFindingLocation();
// register content observer for changes in System Settings
this.getContentResolver().registerContentObserver(android.provider.Settings.Secure.CONTENT_URI, true, mSettingsContentObserver );
} }
// ACTION STOP
else if (intent.getAction().equals(ACTION_STOP)) { private void stopTracking() {
LogHelper.v(LOG_TAG, "Service received command: STOP"); LogHelper.v(LOG_TAG, "Service received command: STOP");
// store current date and time
mTrack.setRecordingEnd(GregorianCalendar.getInstance().getTime());
// stop timer // stop timer
mTimer.cancel(); mTimer.cancel();
@ -146,53 +230,9 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
// remove listeners // remove listeners
stopFindingLocation(); stopFindingLocation();
mSensorManager.unregisterListener(this); mSensorManager.unregisterListener(this);
}
// 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.");
// remove listeners
stopFindingLocation();
mSensorManager.unregisterListener(this);
// cancel notification
stopForeground(true);
super.onDestroy();
}
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
// save the step count offset / previously recorded steps
if (mStepCountOffset == 0) {
mStepCountOffset = sensorEvent.values[0] - 1;
}
// calculate step count
float stepCount = sensorEvent.values[0] - mStepCountOffset;
// set step count in track
mTrack.setStepCount(stepCount);
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
// disable content observer for changes in System Settings
this.getContentResolver().unregisterContentObserver(mSettingsContentObserver);
} }
@ -242,7 +282,7 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
} }
public void onStatusChanged(String provider, int status, Bundle extras) { public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO do something LogHelper.v(LOG_TAG, "Location provider status change: " + provider + " | " + status);
} }
public void onProviderEnabled(String provider) { public void onProviderEnabled(String provider) {
@ -260,13 +300,14 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
private void startFindingLocation() { private void startFindingLocation() {
// register location listeners and request updates // register location listeners and request updates
List locationProviders = mLocationManager.getProviders(true); List locationProviders = mLocationManager.getAllProviders();
if (locationProviders.contains(LocationManager.GPS_PROVIDER)) { if (locationProviders.contains(LocationManager.GPS_PROVIDER)) {
mGPSListener = createLocationListener(); mGPSListener = createLocationListener();
} else if (locationProviders.contains(LocationManager.NETWORK_PROVIDER)) { } else if (locationProviders.contains(LocationManager.NETWORK_PROVIDER)) {
mNetworkListener = createLocationListener(); mNetworkListener = createLocationListener();
} }
LocationHelper.registerLocationListeners(mLocationManager, mGPSListener, mNetworkListener); LocationHelper.registerLocationListeners(mLocationManager, mGPSListener, mNetworkListener);
mTrackerServiceRunning = true;
} }
@ -274,6 +315,7 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
private void stopFindingLocation() { private void stopFindingLocation() {
// remove listeners // remove listeners
LocationHelper.removeLocationListeners(mLocationManager, mGPSListener, mNetworkListener); LocationHelper.removeLocationListeners(mLocationManager, mGPSListener, mNetworkListener);
mTrackerServiceRunning = false;
// notify MainActivityMapFragment // notify MainActivityMapFragment
Intent i = new Intent(); Intent i = new Intent();
@ -281,7 +323,40 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven
i.putExtra(EXTRA_TRACK, mTrack); i.putExtra(EXTRA_TRACK, mTrack);
i.putExtra(EXTRA_LAST_LOCATION, mCurrentBestLocation); i.putExtra(EXTRA_LAST_LOCATION, mCurrentBestLocation);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(i); LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(i);
}
/**
* Inner class: SettingsContentObserver is a custom ContentObserver for changes in Android Settings
*/
public class SettingsContentObserver extends ContentObserver {
public SettingsContentObserver(Handler handler) {
super(handler);
}
@Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
LogHelper.v(LOG_TAG, "System Setting change detected.");
// check if location setting was changed
boolean previousLocationSystemSetting = mLocationSystemSetting;
mLocationSystemSetting = LocationHelper.checkLocationSystemSetting(getApplicationContext());
if (previousLocationSystemSetting != mLocationSystemSetting && !mLocationSystemSetting && mTrackerServiceRunning) {
LogHelper.v(LOG_TAG, "Location Setting turned off while tracking service running.");
stopTracking();
stopForeground(true);
}
}
} }
} }

View File

@ -26,6 +26,8 @@ import org.y20k.trackbook.helpers.TrackbookKeys;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -45,6 +47,8 @@ public class Track implements TrackbookKeys, Parcelable {
private long mDuration; private long mDuration;
private float mStepCount; private float mStepCount;
private int mUnitSystem; private int mUnitSystem;
private Date mRecordingStart;
private Date mRecordingEnd;
/* Constructor */ /* Constructor */
@ -53,6 +57,8 @@ public class Track implements TrackbookKeys, Parcelable {
mTrackLength = 0; mTrackLength = 0;
mStepCount = 0; mStepCount = 0;
mUnitSystem = getUnitSystem(Locale.getDefault()); mUnitSystem = getUnitSystem(Locale.getDefault());
mRecordingStart = GregorianCalendar.getInstance().getTime();
mRecordingEnd = mRecordingStart;
} }
@ -62,6 +68,8 @@ public class Track implements TrackbookKeys, Parcelable {
mTrackLength = in.readFloat(); mTrackLength = in.readFloat();
mStepCount = in.readFloat(); mStepCount = in.readFloat();
mUnitSystem = in.readInt(); mUnitSystem = in.readInt();
mRecordingStart = new Date(in.readLong());
mRecordingEnd = new Date(in.readLong());
} }
@ -108,6 +116,12 @@ public class Track implements TrackbookKeys, Parcelable {
} }
/* Setter for end time and date of recording */
public void setRecordingEnd (Date recordingEnd) {
mRecordingEnd = recordingEnd;
}
/* Setter for duration of track */ /* Setter for duration of track */
public void setDuration(long duration) { public void setDuration(long duration) {
mDuration = duration; mDuration = duration;
@ -119,6 +133,7 @@ public class Track implements TrackbookKeys, Parcelable {
mStepCount = stepCount; mStepCount = stepCount;
} }
/* Getter for mWayPoints */ /* Getter for mWayPoints */
public List<WayPoint> getWayPoints() { public List<WayPoint> getWayPoints() {
return mWayPoints; return mWayPoints;
@ -188,6 +203,8 @@ public class Track implements TrackbookKeys, Parcelable {
parcel.writeFloat(mTrackLength); parcel.writeFloat(mTrackLength);
parcel.writeFloat(mStepCount); parcel.writeFloat(mStepCount);
parcel.writeInt(mUnitSystem); parcel.writeInt(mUnitSystem);
parcel.writeLong(mRecordingStart.getTime());
parcel.writeLong(mRecordingEnd.getTime());
} }

View File

@ -16,10 +16,12 @@
package org.y20k.trackbook.helpers; package org.y20k.trackbook.helpers;
import android.content.Context;
import android.location.Location; import android.location.Location;
import android.location.LocationListener; import android.location.LocationListener;
import android.location.LocationManager; import android.location.LocationManager;
import android.os.SystemClock; import android.os.SystemClock;
import android.provider.Settings;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -162,6 +164,7 @@ public final class LocationHelper implements TrackbookKeys {
try { try {
// register GPS location listener and request updates // register GPS location listener and request updates
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, gpsListener); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, gpsListener);
LogHelper.v(LOG_TAG, "Registering gps listener.");
} catch (SecurityException e) { } catch (SecurityException e) {
// catches permission problems // catches permission problems
e.printStackTrace(); e.printStackTrace();
@ -173,6 +176,7 @@ public final class LocationHelper implements TrackbookKeys {
try { try {
// register network location listener and request updates // register network location listener and request updates
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, networkListener); locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, networkListener);
LogHelper.v(LOG_TAG, "Registering network listener.");
} catch (SecurityException e) { } catch (SecurityException e) {
// catches permission problems // catches permission problems
e.printStackTrace(); e.printStackTrace();
@ -186,13 +190,14 @@ public final class LocationHelper implements TrackbookKeys {
LogHelper.v(LOG_TAG, "Removing location listeners."); LogHelper.v(LOG_TAG, "Removing location listeners.");
// get location providers // get location providers
List locationProviders = locationManager.getProviders(true); List locationProviders = locationManager.getAllProviders();
// got GPS location provider? // got GPS location provider?
if (locationProviders.contains(LocationManager.GPS_PROVIDER) && gpsListener != null) { if (locationProviders.contains(LocationManager.GPS_PROVIDER) && gpsListener != null) {
try { try {
// remove GPS listener // remove GPS listener
locationManager.removeUpdates(gpsListener); locationManager.removeUpdates(gpsListener);
LogHelper.v(LOG_TAG, "Removing gps listener.");
} catch (SecurityException e) { } catch (SecurityException e) {
// catches permission problems // catches permission problems
e.printStackTrace(); e.printStackTrace();
@ -204,6 +209,7 @@ public final class LocationHelper implements TrackbookKeys {
try { try {
// remove network listener // remove network listener
locationManager.removeUpdates(networkListener); locationManager.removeUpdates(networkListener);
LogHelper.v(LOG_TAG, "Removing network listener.");
} catch (SecurityException e) { } catch (SecurityException e) {
// catches permission problems // catches permission problems
e.printStackTrace(); e.printStackTrace();
@ -232,6 +238,17 @@ public final class LocationHelper implements TrackbookKeys {
} }
/* Check if any location provider is enabled */
public static boolean checkLocationSystemSetting(Context context) {
int locationSettingState = 0;
try {
locationSettingState = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
return locationSettingState != Settings.Secure.LOCATION_MODE_OFF;
}
/* Checks whether two location providers are the same */ /* Checks whether two location providers are the same */
private static boolean isSameProvider(String provider1, String provider2) { private static boolean isSameProvider(String provider1, String provider2) {

View File

@ -80,5 +80,6 @@ public interface TrackbookKeys {
int INFOSHEET_CONTENT_ABOUT = 1; int INFOSHEET_CONTENT_ABOUT = 1;
int METRIC = 1; int METRIC = 1;
int IMPERIAL = 2; int IMPERIAL = 2;
double DEFAULT_LATITUDE = 49.41667; // latitude Nordkapp, Norway
double DEFAULT_LONGITUDE = 8.67201; // longitude Nordkapp, Norway
} }

View File

@ -100,7 +100,7 @@
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Recording sterted: " android:text="Recording started: "
android:textAppearance="@android:style/TextAppearance.Small.Inverse" /> android:textAppearance="@android:style/TextAppearance.Small.Inverse" />
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -18,18 +18,19 @@
<string name="notification_title_trackbook_running">Trackbook running</string> <string name="notification_title_trackbook_running">Trackbook running</string>
<string name="notification_title_trackbook_not_running">Trackbook not running</string> <string name="notification_title_trackbook_not_running">Trackbook not running</string>
<string name="notification_stop">Stop</string> <string name="notification_stop">Stop</string>
<string name="notification_swipe_to_clear_map">&#8230; swipe to clear map.</string> <string name="notification_swipe_to_clear_map">SWIPE to clear map.</string>
<string name="notification_content_duration">Duration</string> <string name="notification_content_duration">Duration</string>
<string name="notification_content_distance">Distance</string> <string name="notification_content_distance">Distance</string>
<!-- snackbar messages --> <!-- snackbar messages -->
<string name="snackbar_message_tracking_stopped">Tracking stopped</string> <string name="snackbar_message_tracking_stopped">Tracking stopped</string>
<string name="snackbar_message_tracking_started">Tracking started</string> <string name="snackbar_message_tracking_started">Tracking started</string>
<string name="snackbar_message_location_offline">Location is turned off. Trackbook will not work.</string>
<!-- toast messages --> <!-- toast messages -->
<string name="toast_message_permissions_granted">Permissions granted.</string> <string name="toast_message_permissions_granted">Permissions granted.</string>
<string name="toast_message_unable_to_start_app">Unable to start Trackbook.</string> <string name="toast_message_unable_to_start_app">Unable to start Trackbook.</string>
<string name="toast_message_location_offline">Location is turned off.</string> <string name="toast_message_location_offline">Location is turned off. Trackbook will not work.</string>
<string name="toast_message_acquiring_location">Acquiring current location.</string> <string name="toast_message_acquiring_location">Acquiring current location.</string>
<string name="toast_message_last_location">Last location:</string> <string name="toast_message_last_location">Last location:</string>
<string name="toast_message_clear_map">Clearing map.</string> <string name="toast_message_clear_map">Clearing map.</string>
@ -64,7 +65,7 @@
<string name="infosheet_about_h3_internet">Permission INTERNET</string> <string name="infosheet_about_h3_internet">Permission INTERNET</string>
<string name="infosheet_about_p_internet">Trackbook needs to download map data from Open Street Map servers and therefore needs access to the internet.</string> <string name="infosheet_about_p_internet">Trackbook needs to download map data from Open Street Map servers and therefore needs access to the internet.</string>
<string name="infosheet_about_h3_network">Permission ACCESS_WIFI_STATE and ACCESS_NETWORK_STATE</string> <string name="infosheet_about_h3_network">Permission ACCESS_WIFI_STATE and ACCESS_NETWORK_STATE</string>
<string name="infosheet_about_p_network">Trackbook uses to draw its main map. osmdroid needs to know the current state of your devices connectivity. I am not sure why though. On the other hand: These permissions are not harmful in any way.</string> <string name="infosheet_about_p_network">Trackbook uses osmdroid to draw its maps. osmdroid needs to know the current state of your devices connectivity.</string>
<string name="infosheet_about_h3_location">Permission ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION</string> <string name="infosheet_about_h3_location">Permission ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION</string>
<string name="infosheet_about_p_location">Trackbook needs accurate GPS location data to be able to record your movements. If the GPS data is not available or not accurate enough Trackbook uses location data from cell tower and WiFi triangulation.</string> <string name="infosheet_about_p_location">Trackbook needs accurate GPS location data to be able to record your movements. If the GPS data is not available or not accurate enough Trackbook uses location data from cell tower and WiFi triangulation.</string>
<string name="infosheet_about_h3_external">Permission WRITE_EXTERNAL_STORAGE</string> <string name="infosheet_about_h3_external">Permission WRITE_EXTERNAL_STORAGE</string>