checkpoint
This commit is contained in:
parent
5dad3d6209
commit
1f695958e7
5 changed files with 183 additions and 134 deletions
|
@ -1,11 +1,14 @@
|
||||||
package org.y20k.trackbook
|
package org.y20k.trackbook
|
||||||
|
import android.content.ContentValues
|
||||||
import android.database.sqlite.SQLiteDatabase
|
import android.database.sqlite.SQLiteDatabase
|
||||||
import android.database.sqlite.SQLiteDatabase.openOrCreateDatabase
|
import android.database.sqlite.SQLiteDatabase.openOrCreateDatabase
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class Database()
|
class Database(trackbook: Trackbook)
|
||||||
{
|
{
|
||||||
|
val trackbook = trackbook
|
||||||
var ready: Boolean = false
|
var ready: Boolean = false
|
||||||
lateinit var file: File
|
lateinit var file: File
|
||||||
lateinit var connection: SQLiteDatabase
|
lateinit var connection: SQLiteDatabase
|
||||||
|
@ -14,6 +17,7 @@ class Database()
|
||||||
{
|
{
|
||||||
this.connection.close()
|
this.connection.close()
|
||||||
this.ready = false
|
this.ready = false
|
||||||
|
this.trackbook.call_database_changed_listeners()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun connect(file: File)
|
fun connect(file: File)
|
||||||
|
@ -23,6 +27,7 @@ class Database()
|
||||||
this.connection = openOrCreateDatabase(file, null)
|
this.connection = openOrCreateDatabase(file, null)
|
||||||
this.initialize_tables()
|
this.initialize_tables()
|
||||||
this.ready = true
|
this.ready = true
|
||||||
|
Log.i("VOUSSOIR", "Database.open: Calling all listeners")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun commit()
|
fun commit()
|
||||||
|
@ -40,11 +45,29 @@ class Database()
|
||||||
this.connection.endTransaction()
|
this.connection.endTransaction()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun insert_trkpt(device_id: String, trkpt: Trkpt)
|
||||||
|
{
|
||||||
|
val values = ContentValues().apply {
|
||||||
|
put("device_id", device_id)
|
||||||
|
put("lat", trkpt.latitude)
|
||||||
|
put("lon", trkpt.longitude)
|
||||||
|
put("time", GregorianCalendar.getInstance().time.time)
|
||||||
|
put("accuracy", trkpt.accuracy)
|
||||||
|
put("sat", trkpt.numberSatellites)
|
||||||
|
put("ele", trkpt.altitude)
|
||||||
|
}
|
||||||
|
if (! connection.inTransaction())
|
||||||
|
{
|
||||||
|
connection.beginTransaction()
|
||||||
|
}
|
||||||
|
connection.insert("trkpt", null, values)
|
||||||
|
}
|
||||||
|
|
||||||
private fun initialize_tables()
|
private fun initialize_tables()
|
||||||
{
|
{
|
||||||
this.connection.beginTransaction()
|
this.connection.beginTransaction()
|
||||||
this.connection.execSQL("CREATE TABLE IF NOT EXISTS meta(name TEXT PRIMARY KEY, value TEXT)")
|
this.connection.execSQL("CREATE TABLE IF NOT EXISTS meta(name TEXT PRIMARY KEY, value TEXT)")
|
||||||
this.connection.execSQL("CREATE TABLE IF NOT EXISTS trkpt(lat REAL NOT NULL, lon REAL NOT NULL, time INTEGER NOT NULL, accuracy REAL, device_id INTEGER NOT NULL, ele INTEGER, sat INTEGER, star INTEGER, PRIMARY KEY(lat, lon, time, device_id))")
|
this.connection.execSQL("CREATE TABLE IF NOT EXISTS trkpt(lat REAL NOT NULL, lon REAL NOT NULL, time INTEGER NOT NULL, accuracy REAL, device_id INTEGER NOT NULL, ele INTEGER, sat INTEGER, PRIMARY KEY(lat, lon, time, device_id))")
|
||||||
this.connection.execSQL("CREATE TABLE IF NOT EXISTS homepoints(lat REAL NOT NULL, lon REAL NOT NULL, radius REAL NOT NULL, name TEXT, PRIMARY KEY(lat, lon))")
|
this.connection.execSQL("CREATE TABLE IF NOT EXISTS homepoints(lat REAL NOT NULL, lon REAL NOT NULL, radius REAL NOT NULL, name TEXT, PRIMARY KEY(lat, lon))")
|
||||||
this.connection.setTransactionSuccessful()
|
this.connection.setTransactionSuccessful()
|
||||||
this.connection.endTransaction()
|
this.connection.endTransaction()
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
package org.y20k.trackbook
|
package org.y20k.trackbook
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.Activity
|
|
||||||
import android.content.*
|
import android.content.*
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
|
@ -41,8 +40,8 @@ import org.osmdroid.api.IMapController
|
||||||
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
|
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
|
||||||
import org.osmdroid.util.GeoPoint
|
import org.osmdroid.util.GeoPoint
|
||||||
import org.osmdroid.views.MapView
|
import org.osmdroid.views.MapView
|
||||||
import org.osmdroid.views.overlay.FolderOverlay
|
|
||||||
import org.osmdroid.views.overlay.ItemizedIconOverlay
|
import org.osmdroid.views.overlay.ItemizedIconOverlay
|
||||||
|
import org.osmdroid.views.overlay.Overlay
|
||||||
import org.osmdroid.views.overlay.OverlayItem
|
import org.osmdroid.views.overlay.OverlayItem
|
||||||
import org.osmdroid.views.overlay.Polygon
|
import org.osmdroid.views.overlay.Polygon
|
||||||
import org.osmdroid.views.overlay.TilesOverlay
|
import org.osmdroid.views.overlay.TilesOverlay
|
||||||
|
@ -69,30 +68,44 @@ class MapFragment : Fragment()
|
||||||
private lateinit var currentBestLocation: Location
|
private lateinit var currentBestLocation: Location
|
||||||
private lateinit var trackerService: TrackerService
|
private lateinit var trackerService: TrackerService
|
||||||
|
|
||||||
|
private lateinit var trackbook: Trackbook
|
||||||
lateinit var rootView: View
|
lateinit var rootView: View
|
||||||
var userInteraction: Boolean = false
|
var userInteraction: Boolean = false
|
||||||
lateinit var currentLocationButton: FloatingActionButton
|
lateinit var currentLocationButton: FloatingActionButton
|
||||||
lateinit var mainButton: ExtendedFloatingActionButton
|
lateinit var mainButton: ExtendedFloatingActionButton
|
||||||
private lateinit var mapView: MapView
|
private lateinit var mapView: MapView
|
||||||
private lateinit var current_position_folder: FolderOverlay
|
private var current_position_overlays = ArrayList<Overlay>()
|
||||||
private var currentTrackOverlay: SimpleFastPointOverlay? = null
|
private var currentTrackOverlay: SimpleFastPointOverlay? = null
|
||||||
private var currentTrackSpecialMarkerOverlay: ItemizedIconOverlay<OverlayItem>? = null
|
private var currentTrackSpecialMarkerOverlay: ItemizedIconOverlay<OverlayItem>? = null
|
||||||
private lateinit var locationErrorBar: Snackbar
|
private lateinit var locationErrorBar: Snackbar
|
||||||
private lateinit var controller: IMapController
|
private lateinit var controller: IMapController
|
||||||
private var zoomLevel: Double = Keys.DEFAULT_ZOOM_LEVEL
|
private var zoomLevel: Double = Keys.DEFAULT_ZOOM_LEVEL
|
||||||
private lateinit var homepoints_overlay_folder: FolderOverlay
|
private var homepoints_overlays = ArrayList<Overlay>()
|
||||||
|
private lateinit var database_changed_listener: DatabaseChangedListener
|
||||||
|
|
||||||
/* Overrides onCreate from Fragment */
|
/* Overrides onCreate from Fragment */
|
||||||
override fun onCreate(savedInstanceState: Bundle?)
|
override fun onCreate(savedInstanceState: Bundle?)
|
||||||
{
|
{
|
||||||
Log.i("VOUSSOIR", "MapFragment.onCreate")
|
Log.i("VOUSSOIR", "MapFragment.onCreate")
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
// TODO make only MapFragment's status bar transparent - see:
|
this.trackbook = (requireContext().applicationContext as Trackbook)
|
||||||
// https://gist.github.com/Dvik/a3de88d39da9d1d6d175025a56c5e797#file-viewextension-kt and
|
database_changed_listener = object: DatabaseChangedListener
|
||||||
// https://proandroiddev.com/android-full-screen-ui-with-transparent-status-bar-ef52f3adde63
|
{
|
||||||
// get current best location
|
override fun database_changed()
|
||||||
currentBestLocation = getLastKnownLocation(activity as Context)
|
{
|
||||||
// get saved tracking state
|
Log.i("VOUSSOIR", "MapFragment database_ready_changed to ${trackbook.database.ready}")
|
||||||
|
if (trackbook.database.ready)
|
||||||
|
{
|
||||||
|
create_homepoint_overlays(requireContext(), mapView, trackbook.homepoints)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clear_homepoint_overlays()
|
||||||
|
}
|
||||||
|
update_main_button()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentBestLocation = getLastKnownLocation(requireContext())
|
||||||
trackingState = PreferencesHelper.loadTrackingState()
|
trackingState = PreferencesHelper.loadTrackingState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +113,6 @@ class MapFragment : Fragment()
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View
|
||||||
{
|
{
|
||||||
Log.i("VOUSSOIR", "MapFragment.onCreateView")
|
Log.i("VOUSSOIR", "MapFragment.onCreateView")
|
||||||
val context = activity as Context
|
|
||||||
// find views
|
// find views
|
||||||
rootView = inflater.inflate(R.layout.fragment_map, container, false)
|
rootView = inflater.inflate(R.layout.fragment_map, container, false)
|
||||||
mapView = rootView.findViewById(R.id.map)
|
mapView = rootView.findViewById(R.id.map)
|
||||||
|
@ -124,26 +136,23 @@ class MapFragment : Fragment()
|
||||||
}
|
}
|
||||||
|
|
||||||
// store Density Scaling Factor
|
// store Density Scaling Factor
|
||||||
val densityScalingFactor: Float = UiHelper.getDensityScalingFactor(context)
|
val densityScalingFactor: Float = UiHelper.getDensityScalingFactor(requireContext())
|
||||||
|
|
||||||
// add compass to map
|
// add compass to map
|
||||||
val compassOverlay = CompassOverlay(context, InternalCompassOrientationProvider(context), mapView)
|
val compassOverlay = CompassOverlay(requireContext(), InternalCompassOrientationProvider(requireContext()), mapView)
|
||||||
compassOverlay.enableCompass()
|
compassOverlay.enableCompass()
|
||||||
// compassOverlay.setCompassCenter(36f, 36f + (statusBarHeight / densityScalingFactor)) // TODO uncomment when transparent status bar is re-implemented
|
// compassOverlay.setCompassCenter(36f, 36f + (statusBarHeight / densityScalingFactor)) // TODO uncomment when transparent status bar is re-implemented
|
||||||
val screen_width = Resources.getSystem().displayMetrics.widthPixels;
|
val screen_width = Resources.getSystem().displayMetrics.widthPixels;
|
||||||
compassOverlay.setCompassCenter((screen_width / densityScalingFactor) - 36f, 36f)
|
compassOverlay.setCompassCenter((screen_width / densityScalingFactor) - 36f, 36f)
|
||||||
mapView.overlays.add(compassOverlay)
|
mapView.overlays.add(compassOverlay)
|
||||||
|
|
||||||
val app: Trackbook = (context.applicationContext as Trackbook)
|
val app: Trackbook = (requireContext().applicationContext as Trackbook)
|
||||||
app.load_homepoints()
|
app.load_homepoints()
|
||||||
homepoints_overlay_folder = FolderOverlay()
|
create_homepoint_overlays(requireContext(), mapView, app.homepoints)
|
||||||
mapView.overlays.add(homepoints_overlay_folder)
|
if (database_changed_listener !in trackbook.database_changed_listeners)
|
||||||
createHomepointOverlays(context, mapView, app.homepoints)
|
{
|
||||||
|
trackbook.database_changed_listeners.add(database_changed_listener)
|
||||||
// add my location overlay
|
}
|
||||||
current_position_folder = FolderOverlay()
|
|
||||||
mapView.overlays.add(current_position_folder)
|
|
||||||
|
|
||||||
|
|
||||||
centerMap(currentBestLocation)
|
centerMap(currentBestLocation)
|
||||||
|
|
||||||
|
@ -152,7 +161,7 @@ class MapFragment : Fragment()
|
||||||
currentTrackSpecialMarkerOverlay = null
|
currentTrackSpecialMarkerOverlay = null
|
||||||
|
|
||||||
// initialize main button state
|
// initialize main button state
|
||||||
updateMainButton(trackingState)
|
update_main_button()
|
||||||
|
|
||||||
// listen for user interaction
|
// listen for user interaction
|
||||||
addInteractionListener()
|
addInteractionListener()
|
||||||
|
@ -224,9 +233,13 @@ class MapFragment : Fragment()
|
||||||
Log.i("VOUSSOIR", "MapFragment.onDestroy")
|
Log.i("VOUSSOIR", "MapFragment.onDestroy")
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
|
|
||||||
|
if (database_changed_listener in trackbook.database_changed_listeners)
|
||||||
|
{
|
||||||
|
trackbook.database_changed_listeners.remove(database_changed_listener)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register the permission launcher for requesting location */
|
|
||||||
private val requestLocationPermissionLauncher = registerForActivityResult(RequestPermission()) { isGranted: Boolean ->
|
private val requestLocationPermissionLauncher = registerForActivityResult(RequestPermission()) { isGranted: Boolean ->
|
||||||
if (isGranted) {
|
if (isGranted) {
|
||||||
// permission was granted - re-bind service
|
// permission was granted - re-bind service
|
||||||
|
@ -301,9 +314,6 @@ class MapFragment : Fragment()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Defines the listener for changes in shared preferences
|
|
||||||
*/
|
|
||||||
private val sharedPreferenceChangeListener = SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
|
private val sharedPreferenceChangeListener = SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
|
||||||
when (key)
|
when (key)
|
||||||
{
|
{
|
||||||
|
@ -312,12 +322,14 @@ class MapFragment : Fragment()
|
||||||
if (activity != null)
|
if (activity != null)
|
||||||
{
|
{
|
||||||
trackingState = PreferencesHelper.loadTrackingState()
|
trackingState = PreferencesHelper.loadTrackingState()
|
||||||
updateMainButton(trackingState)
|
update_main_button()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private fun addInteractionListener() {
|
|
||||||
|
private fun addInteractionListener()
|
||||||
|
{
|
||||||
mapView.setOnTouchListener { v, event ->
|
mapView.setOnTouchListener { v, event ->
|
||||||
userInteraction = true
|
userInteraction = true
|
||||||
false
|
false
|
||||||
|
@ -340,10 +352,25 @@ class MapFragment : Fragment()
|
||||||
userInteraction = false
|
userInteraction = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clear_current_position_overlays()
|
||||||
|
{
|
||||||
|
for (ov in current_position_overlays)
|
||||||
|
{
|
||||||
|
if (ov in mapView.overlays)
|
||||||
|
{
|
||||||
|
mapView.overlays.remove(ov)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current_position_overlays.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/* Mark current position on map */
|
/* Mark current position on map */
|
||||||
fun markCurrentPosition(location: Location, trackingState: Int = Keys.STATE_TRACKING_STOPPED)
|
fun create_current_position_overlays(location: Location, trackingState: Int = Keys.STATE_TRACKING_STOPPED)
|
||||||
{
|
{
|
||||||
Log.i("VOUSSOIR", "MapFragmentLayoutHolder.markCurrentPosition")
|
Log.i("VOUSSOIR", "MapFragmentLayoutHolder.markCurrentPosition")
|
||||||
|
|
||||||
|
clear_current_position_overlays()
|
||||||
|
|
||||||
val locationIsOld: Boolean = !(isRecentEnough(location))
|
val locationIsOld: Boolean = !(isRecentEnough(location))
|
||||||
|
|
||||||
// create marker
|
// create marker
|
||||||
|
@ -374,47 +401,68 @@ class MapFragment : Fragment()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
current_position_folder.items.clear()
|
|
||||||
|
|
||||||
val current_location_radius = Polygon()
|
val current_location_radius = Polygon()
|
||||||
current_location_radius.points = Polygon.pointsAsCircle(GeoPoint(location.latitude, location.longitude), location.accuracy.toDouble())
|
current_location_radius.points = Polygon.pointsAsCircle(GeoPoint(location.latitude, location.longitude), location.accuracy.toDouble())
|
||||||
current_location_radius.fillPaint.color = fillcolor
|
current_location_radius.fillPaint.color = fillcolor
|
||||||
current_location_radius.outlinePaint.color = Color.argb(0, 0, 0, 0)
|
current_location_radius.outlinePaint.color = Color.argb(0, 0, 0, 0)
|
||||||
current_position_folder.add(current_location_radius)
|
current_position_overlays.add(current_location_radius)
|
||||||
|
|
||||||
val overlayItems: java.util.ArrayList<OverlayItem> = java.util.ArrayList<OverlayItem>()
|
val overlayItems: java.util.ArrayList<OverlayItem> = java.util.ArrayList<OverlayItem>()
|
||||||
val overlayItem: OverlayItem = createOverlayItem(requireContext(), location.latitude, location.longitude, location.accuracy, location.provider.toString(), location.time)
|
val overlayItem: OverlayItem = createOverlayItem(requireContext(), location.latitude, location.longitude, location.accuracy, location.provider.toString(), location.time)
|
||||||
overlayItem.setMarker(newMarker)
|
overlayItem.setMarker(newMarker)
|
||||||
overlayItems.add(overlayItem)
|
overlayItems.add(overlayItem)
|
||||||
current_position_folder.add(createOverlay(requireContext(), overlayItems))
|
current_position_overlays.add(createOverlay(requireContext(), overlayItems))
|
||||||
|
|
||||||
|
for (ov in current_position_overlays)
|
||||||
|
{
|
||||||
|
mapView.overlays.add(ov)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createHomepointOverlays(context: Context, map_view: MapView, homepoints: List<Homepoint>)
|
fun clear_homepoint_overlays()
|
||||||
|
{
|
||||||
|
for (ov in homepoints_overlays)
|
||||||
|
{
|
||||||
|
if (ov in mapView.overlays)
|
||||||
|
{
|
||||||
|
mapView.overlays.remove(ov)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
homepoints_overlays.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fun create_homepoint_overlays(context: Context, map_view: MapView, homepoints: List<Homepoint>)
|
||||||
{
|
{
|
||||||
Log.i("VOUSSOIR", "MapFragmentLayoutHolder.createHomepointOverlays")
|
Log.i("VOUSSOIR", "MapFragmentLayoutHolder.createHomepointOverlays")
|
||||||
val overlayItems: java.util.ArrayList<OverlayItem> = java.util.ArrayList<OverlayItem>()
|
val overlayItems: java.util.ArrayList<OverlayItem> = java.util.ArrayList<OverlayItem>()
|
||||||
|
|
||||||
val newMarker: Drawable = ContextCompat.getDrawable(context, R.drawable.ic_homepoint_24dp)!!
|
val newMarker: Drawable = ContextCompat.getDrawable(context, R.drawable.ic_homepoint_24dp)!!
|
||||||
|
|
||||||
homepoints_overlay_folder.items.clear()
|
clear_homepoint_overlays()
|
||||||
|
|
||||||
for (homepoint in homepoints)
|
for (homepoint in homepoints)
|
||||||
{
|
{
|
||||||
val overlayItem: OverlayItem = createOverlayItem(context, homepoint.location.latitude, homepoint.location.longitude, homepoint.location.accuracy, homepoint.location.provider.toString(), homepoint.location.time)
|
|
||||||
overlayItem.setMarker(newMarker)
|
|
||||||
overlayItems.add(overlayItem)
|
|
||||||
homepoints_overlay_folder.add(createOverlay(context, overlayItems))
|
|
||||||
|
|
||||||
val p = Polygon()
|
val p = Polygon()
|
||||||
p.points = Polygon.pointsAsCircle(GeoPoint(homepoint.location.latitude, homepoint.location.longitude), homepoint.location.accuracy.toDouble())
|
p.points = Polygon.pointsAsCircle(GeoPoint(homepoint.location.latitude, homepoint.location.longitude), homepoint.location.accuracy.toDouble())
|
||||||
p.fillPaint.color = Color.argb(64, 255, 193, 7)
|
p.fillPaint.color = Color.argb(64, 255, 193, 7)
|
||||||
p.outlinePaint.color = Color.argb(0, 0, 0, 0)
|
p.outlinePaint.color = Color.argb(0, 0, 0, 0)
|
||||||
homepoints_overlay_folder.add(p)
|
homepoints_overlays.add(p)
|
||||||
|
|
||||||
|
val overlayItem: OverlayItem = createOverlayItem(context, homepoint.location.latitude, homepoint.location.longitude, homepoint.location.accuracy, homepoint.location.provider.toString(), homepoint.location.time)
|
||||||
|
overlayItem.setMarker(newMarker)
|
||||||
|
overlayItems.add(overlayItem)
|
||||||
|
homepoints_overlays.add(createOverlay(context, overlayItems))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ov in homepoints_overlays)
|
||||||
|
{
|
||||||
|
mapView.overlays.add(ov)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Overlay current track on map */
|
/* Overlay current track on map */
|
||||||
fun overlayCurrentTrack(track: Track, trackingState: Int) {
|
fun create_current_track_overlay(track: Track, trackingState: Int)
|
||||||
|
{
|
||||||
if (currentTrackOverlay != null) {
|
if (currentTrackOverlay != null) {
|
||||||
mapView.overlays.remove(currentTrackOverlay)
|
mapView.overlays.remove(currentTrackOverlay)
|
||||||
}
|
}
|
||||||
|
@ -427,22 +475,26 @@ class MapFragment : Fragment()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Toggles state of main button and additional buttons (save & resume) */
|
fun update_main_button()
|
||||||
fun updateMainButton(trackingState: Int)
|
|
||||||
{
|
{
|
||||||
when (trackingState) {
|
mainButton.isEnabled = trackbook.database.ready
|
||||||
Keys.STATE_TRACKING_STOPPED -> {
|
currentLocationButton.isVisible = true
|
||||||
mainButton.setIconResource(R.drawable.ic_fiber_manual_record_inactive_24dp)
|
if (! trackbook.database.ready)
|
||||||
mainButton.text = requireContext().getString(R.string.button_start)
|
{
|
||||||
mainButton.contentDescription = requireContext().getString(R.string.descr_button_start)
|
mainButton.text = "Database not ready"
|
||||||
currentLocationButton.isVisible = true
|
mainButton.icon = null
|
||||||
}
|
}
|
||||||
Keys.STATE_TRACKING_ACTIVE -> {
|
else if (trackingState == Keys.STATE_TRACKING_STOPPED)
|
||||||
mainButton.setIconResource(R.drawable.ic_fiber_manual_stop_24dp)
|
{
|
||||||
mainButton.text = requireContext().getString(R.string.button_pause)
|
mainButton.setIconResource(R.drawable.ic_fiber_manual_record_inactive_24dp)
|
||||||
mainButton.contentDescription = requireContext().getString(R.string.descr_button_pause)
|
mainButton.text = requireContext().getString(R.string.button_start)
|
||||||
currentLocationButton.isVisible = true
|
mainButton.contentDescription = requireContext().getString(R.string.descr_button_start)
|
||||||
}
|
}
|
||||||
|
else if (trackingState == Keys.STATE_TRACKING_ACTIVE)
|
||||||
|
{
|
||||||
|
mainButton.setIconResource(R.drawable.ic_fiber_manual_stop_24dp)
|
||||||
|
mainButton.text = requireContext().getString(R.string.button_pause)
|
||||||
|
mainButton.contentDescription = requireContext().getString(R.string.descr_button_pause)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,13 +511,7 @@ class MapFragment : Fragment()
|
||||||
if (locationErrorBar.isShown) locationErrorBar.dismiss()
|
if (locationErrorBar.isShown) locationErrorBar.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* End of declaration
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Defines callbacks for service binding, passed to bindService()
|
|
||||||
*/
|
|
||||||
private val connection = object : ServiceConnection {
|
private val connection = object : ServiceConnection {
|
||||||
override fun onServiceConnected(className: ComponentName, service: IBinder) {
|
override fun onServiceConnected(className: ComponentName, service: IBinder) {
|
||||||
bound = true
|
bound = true
|
||||||
|
@ -474,7 +520,7 @@ class MapFragment : Fragment()
|
||||||
trackerService = binder.service
|
trackerService = binder.service
|
||||||
// get state of tracking and update button if necessary
|
// get state of tracking and update button if necessary
|
||||||
trackingState = trackerService.trackingState
|
trackingState = trackerService.trackingState
|
||||||
updateMainButton(trackingState)
|
update_main_button()
|
||||||
// register listener for changes in shared preferences
|
// register listener for changes in shared preferences
|
||||||
PreferencesHelper.registerPreferenceChangeListener(sharedPreferenceChangeListener)
|
PreferencesHelper.registerPreferenceChangeListener(sharedPreferenceChangeListener)
|
||||||
// start listening for location updates
|
// start listening for location updates
|
||||||
|
@ -486,13 +532,7 @@ class MapFragment : Fragment()
|
||||||
handleServiceUnbind()
|
handleServiceUnbind()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* End of declaration
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Runnable: Periodically requests location
|
|
||||||
*/
|
|
||||||
private val periodicLocationRequestRunnable: Runnable = object : Runnable {
|
private val periodicLocationRequestRunnable: Runnable = object : Runnable {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
// pull current state from service
|
// pull current state from service
|
||||||
|
@ -502,20 +542,17 @@ class MapFragment : Fragment()
|
||||||
networkProviderActive = trackerService.networkProviderActive
|
networkProviderActive = trackerService.networkProviderActive
|
||||||
trackingState = trackerService.trackingState
|
trackingState = trackerService.trackingState
|
||||||
// update location and track
|
// update location and track
|
||||||
markCurrentPosition(currentBestLocation, trackingState)
|
create_current_position_overlays(currentBestLocation, trackingState)
|
||||||
overlayCurrentTrack(track, trackingState)
|
create_current_track_overlay(track, trackingState)
|
||||||
// center map, if it had not been dragged/zoomed before
|
// center map, if it had not been dragged/zoomed before
|
||||||
if (!userInteraction)
|
if (!userInteraction)
|
||||||
{
|
{
|
||||||
centerMap(currentBestLocation, true)
|
centerMap(currentBestLocation, true)
|
||||||
}
|
}
|
||||||
// show error snackbar if necessary
|
// show error snackbar if necessary
|
||||||
toggleLocationErrorBar(gpsProviderActive, networkProviderActive)
|
// toggleLocationErrorBar(gpsProviderActive, networkProviderActive)
|
||||||
// use the handler to start runnable again after specified delay
|
// use the handler to start runnable again after specified delay
|
||||||
handler.postDelayed(this, Keys.REQUEST_CURRENT_LOCATION_INTERVAL)
|
handler.postDelayed(this, Keys.REQUEST_CURRENT_LOCATION_INTERVAL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* End of declaration
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,12 +31,24 @@ import org.y20k.trackbook.helpers.PreferencesHelper
|
||||||
import org.y20k.trackbook.helpers.PreferencesHelper.initPreferences
|
import org.y20k.trackbook.helpers.PreferencesHelper.initPreferences
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
/*
|
|
||||||
* Trackbook.class
|
interface DatabaseChangedListener
|
||||||
*/
|
{
|
||||||
|
fun database_changed()
|
||||||
|
}
|
||||||
|
|
||||||
class Trackbook(): Application() {
|
class Trackbook(): Application() {
|
||||||
val database: Database = Database()
|
val database: Database = Database(this)
|
||||||
val homepoints: ArrayList<Homepoint> = ArrayList()
|
val homepoints: ArrayList<Homepoint> = ArrayList()
|
||||||
|
val database_changed_listeners = ArrayList<DatabaseChangedListener>()
|
||||||
|
|
||||||
|
fun call_database_changed_listeners()
|
||||||
|
{
|
||||||
|
for (listener in this.database_changed_listeners)
|
||||||
|
{
|
||||||
|
listener.database_changed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate()
|
override fun onCreate()
|
||||||
{
|
{
|
||||||
|
@ -63,6 +75,7 @@ class Trackbook(): Application() {
|
||||||
{
|
{
|
||||||
this.database.ready = false
|
this.database.ready = false
|
||||||
}
|
}
|
||||||
|
this.call_database_changed_listeners()
|
||||||
}
|
}
|
||||||
fun load_homepoints()
|
fun load_homepoints()
|
||||||
{
|
{
|
||||||
|
|
|
@ -230,7 +230,8 @@ class TrackerService: Service(), SensorEventListener
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Overrides onDestroy from Service */
|
/* Overrides onDestroy from Service */
|
||||||
override fun onDestroy() {
|
override fun onDestroy()
|
||||||
|
{
|
||||||
LogHelper.i("VOUSSOIR", "TrackerService.onDestroy.")
|
LogHelper.i("VOUSSOIR", "TrackerService.onDestroy.")
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
if (trackingState == Keys.STATE_TRACKING_ACTIVE)
|
if (trackingState == Keys.STATE_TRACKING_ACTIVE)
|
||||||
|
@ -255,8 +256,10 @@ class TrackerService: Service(), SensorEventListener
|
||||||
/* Overrides onSensorChanged from SensorEventListener */
|
/* Overrides onSensorChanged from SensorEventListener */
|
||||||
override fun onSensorChanged(sensorEvent: SensorEvent?) {
|
override fun onSensorChanged(sensorEvent: SensorEvent?) {
|
||||||
var steps = 0f
|
var steps = 0f
|
||||||
if (sensorEvent != null) {
|
if (sensorEvent != null)
|
||||||
if (stepCountOffset == 0f) {
|
{
|
||||||
|
if (stepCountOffset == 0f)
|
||||||
|
{
|
||||||
// store steps previously recorded by the system
|
// store steps previously recorded by the system
|
||||||
stepCountOffset = (sensorEvent.values[0] - 1) - 0 // subtract any steps recorded during this session in case the app was killed
|
stepCountOffset = (sensorEvent.values[0] - 1) - 0 // subtract any steps recorded during this session in case the app was killed
|
||||||
}
|
}
|
||||||
|
@ -307,22 +310,28 @@ class TrackerService: Service(), SensorEventListener
|
||||||
/* Adds location listeners to location manager */
|
/* Adds location listeners to location manager */
|
||||||
fun removeGpsLocationListener()
|
fun removeGpsLocationListener()
|
||||||
{
|
{
|
||||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
|
||||||
|
{
|
||||||
locationManager.removeUpdates(gpsLocationListener)
|
locationManager.removeUpdates(gpsLocationListener)
|
||||||
gpsLocationListenerRegistered = false
|
gpsLocationListenerRegistered = false
|
||||||
LogHelper.v(TAG, "Removed GPS location listener.")
|
LogHelper.v(TAG, "Removed GPS location listener.")
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LogHelper.w(TAG, "Unable to remove GPS location listener. Location permission is needed.")
|
LogHelper.w(TAG, "Unable to remove GPS location listener. Location permission is needed.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeNetworkLocationListener()
|
fun removeNetworkLocationListener()
|
||||||
{
|
{
|
||||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
|
||||||
|
{
|
||||||
locationManager.removeUpdates(networkLocationListener)
|
locationManager.removeUpdates(networkLocationListener)
|
||||||
networkLocationListenerRegistered = false
|
networkLocationListenerRegistered = false
|
||||||
LogHelper.v(TAG, "Removed Network location listener.")
|
LogHelper.v(TAG, "Removed Network location listener.")
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
LogHelper.w(TAG, "Unable to remove Network location listener. Location permission is needed.")
|
LogHelper.w(TAG, "Unable to remove Network location listener. Location permission is needed.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -330,7 +339,8 @@ class TrackerService: Service(), SensorEventListener
|
||||||
private fun startStepCounter()
|
private fun startStepCounter()
|
||||||
{
|
{
|
||||||
val stepCounterAvailable = sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER), SensorManager.SENSOR_DELAY_UI)
|
val stepCounterAvailable = sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER), SensorManager.SENSOR_DELAY_UI)
|
||||||
if (!stepCounterAvailable) {
|
if (!stepCounterAvailable)
|
||||||
|
{
|
||||||
LogHelper.w(TAG, "Pedometer sensor not available.")
|
LogHelper.w(TAG, "Pedometer sensor not available.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -445,33 +455,18 @@ class TrackerService: Service(), SensorEventListener
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* Runnable: Periodically track updates (if recording active)
|
|
||||||
*/
|
|
||||||
private val periodicTrackUpdate: Runnable = object : Runnable
|
private val periodicTrackUpdate: Runnable = object : Runnable
|
||||||
{
|
{
|
||||||
override fun run() {
|
override fun run() {
|
||||||
val now: Date = GregorianCalendar.getInstance().time
|
val now: Date = GregorianCalendar.getInstance().time
|
||||||
val trkpt: Trkpt = Trkpt(location=currentBestLocation)
|
val trkpt = Trkpt(location=currentBestLocation)
|
||||||
Log.i("VOUSSOIR", "Processing point ${currentBestLocation.latitude}, ${currentBestLocation.longitude} ${now.time}.")
|
Log.i("VOUSSOIR", "Processing point ${currentBestLocation.latitude}, ${currentBestLocation.longitude} ${now.time}.")
|
||||||
if (should_keep_point((currentBestLocation)))
|
if (should_keep_point((currentBestLocation)))
|
||||||
{
|
{
|
||||||
val values = ContentValues().apply {
|
trackbook.database.insert_trkpt(device_id, trkpt)
|
||||||
put("device_id", device_id)
|
|
||||||
put("lat", trkpt.latitude)
|
|
||||||
put("lon", trkpt.longitude)
|
|
||||||
put("time", now.time)
|
|
||||||
put("accuracy", trkpt.accuracy)
|
|
||||||
put("sat", trkpt.numberSatellites)
|
|
||||||
put("ele", trkpt.altitude)
|
|
||||||
put("star", 0)
|
|
||||||
}
|
|
||||||
if (! trackbook.database.connection.inTransaction())
|
|
||||||
{
|
|
||||||
trackbook.database.connection.beginTransaction()
|
|
||||||
}
|
|
||||||
trackbook.database.connection.insert("trkpt", null, values)
|
|
||||||
track.trkpts.add(trkpt)
|
track.trkpts.add(trkpt)
|
||||||
|
|
||||||
while (track.trkpts.size > 7200)
|
while (track.trkpts.size > 7200)
|
||||||
{
|
{
|
||||||
track.trkpts.removeFirst()
|
track.trkpts.removeFirst()
|
||||||
|
@ -479,20 +474,12 @@ class TrackerService: Service(), SensorEventListener
|
||||||
|
|
||||||
if (now.time - lastCommit.time > Keys.SAVE_TEMP_TRACK_INTERVAL)
|
if (now.time - lastCommit.time > Keys.SAVE_TEMP_TRACK_INTERVAL)
|
||||||
{
|
{
|
||||||
if (trackbook.database.connection.inTransaction())
|
trackbook.database.commit()
|
||||||
{
|
|
||||||
trackbook.database.commit()
|
|
||||||
}
|
|
||||||
lastCommit = now
|
lastCommit = now
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// update notification
|
|
||||||
displayNotification()
|
displayNotification()
|
||||||
// re-run this in set interval
|
|
||||||
handler.postDelayed(this, Keys.TRACKING_INTERVAL)
|
handler.postDelayed(this, Keys.TRACKING_INTERVAL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* End of declaration
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,10 @@ import org.osmdroid.util.GeoPoint
|
||||||
import org.osmdroid.views.MapView
|
import org.osmdroid.views.MapView
|
||||||
import org.osmdroid.views.overlay.ItemizedIconOverlay
|
import org.osmdroid.views.overlay.ItemizedIconOverlay
|
||||||
import org.osmdroid.views.overlay.OverlayItem
|
import org.osmdroid.views.overlay.OverlayItem
|
||||||
import org.osmdroid.views.overlay.Polygon
|
|
||||||
import org.osmdroid.views.overlay.simplefastpoint.LabelledGeoPoint
|
import org.osmdroid.views.overlay.simplefastpoint.LabelledGeoPoint
|
||||||
import org.osmdroid.views.overlay.simplefastpoint.SimpleFastPointOverlay
|
import org.osmdroid.views.overlay.simplefastpoint.SimpleFastPointOverlay
|
||||||
import org.osmdroid.views.overlay.simplefastpoint.SimpleFastPointOverlayOptions
|
import org.osmdroid.views.overlay.simplefastpoint.SimpleFastPointOverlayOptions
|
||||||
import org.osmdroid.views.overlay.simplefastpoint.SimplePointTheme
|
import org.osmdroid.views.overlay.simplefastpoint.SimplePointTheme
|
||||||
import org.y20k.trackbook.Homepoint
|
|
||||||
import org.y20k.trackbook.Keys
|
import org.y20k.trackbook.Keys
|
||||||
import org.y20k.trackbook.R
|
import org.y20k.trackbook.R
|
||||||
import org.y20k.trackbook.Track
|
import org.y20k.trackbook.Track
|
||||||
|
@ -44,15 +42,6 @@ import java.text.DecimalFormat
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
//private var currentPositionOverlay: ItemizedIconOverlay<OverlayItem>
|
|
||||||
|
|
||||||
|
|
||||||
/* Creates icon overlay for current position (used in MapFragment) */
|
|
||||||
fun createMyLocationOverlay(context: Context, map_view: MapView, currentPositionOverlay: ItemizedIconOverlay<OverlayItem>, location: Location, trackingState: Int)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Creates icon overlay for track */
|
/* Creates icon overlay for track */
|
||||||
fun createTrackOverlay(context: Context, map_view: MapView, track: Track, trackingState: Int)
|
fun createTrackOverlay(context: Context, map_view: MapView, track: Track, trackingState: Int)
|
||||||
|
@ -149,12 +138,12 @@ fun createOverlay(context: Context, overlayItems: ArrayList<OverlayItem>): Itemi
|
||||||
{
|
{
|
||||||
return ItemizedIconOverlay<OverlayItem>(context, overlayItems,
|
return ItemizedIconOverlay<OverlayItem>(context, overlayItems,
|
||||||
object : ItemizedIconOverlay.OnItemGestureListener<OverlayItem> {
|
object : ItemizedIconOverlay.OnItemGestureListener<OverlayItem> {
|
||||||
override fun onItemSingleTapUp(index: Int, item: OverlayItem): Boolean {
|
override fun onItemSingleTapUp(index: Int, item: OverlayItem): Boolean
|
||||||
|
{
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
override fun onItemLongPress(index: Int, item: OverlayItem): Boolean {
|
override fun onItemLongPress(index: Int, item: OverlayItem): Boolean
|
||||||
val v = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
{
|
||||||
v.vibrate(50)
|
|
||||||
Toast.makeText(context, item.snippet, Toast.LENGTH_LONG).show()
|
Toast.makeText(context, item.snippet, Toast.LENGTH_LONG).show()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue