Compare commits
No commits in common. "29a4a1dae3aeb4dbaca6f15e13b8311a7ba4c483" and "a27b8713a9d59596ef4e44f0a505c60e4b14340f" have entirely different histories.
29a4a1dae3
...
a27b8713a9
7 changed files with 98 additions and 190 deletions
|
|
@ -10,8 +10,8 @@ android {
|
||||||
applicationId 'net.voussoir.trkpt'
|
applicationId 'net.voussoir.trkpt'
|
||||||
minSdkVersion 25
|
minSdkVersion 25
|
||||||
targetSdk 32
|
targetSdk 32
|
||||||
versionCode 58
|
versionCode 56
|
||||||
versionName '1.3.0'
|
versionName '1.2.0'
|
||||||
resConfigs "en", "da", "de", "fr", "hr", "id", "it", "ja", "nb-rNO", "nl", "pl", "pt-rBR", "ru", "sv", "tr", "zh-rCN"
|
resConfigs "en", "da", "de", "fr", "hr", "id", "it", "ja", "nb-rNO", "nl", "pl", "pt-rBR", "ru", "sv", "tr", "zh-rCN"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,11 +56,11 @@ class Database(val trackbook: Trackbook)
|
||||||
this.connection.endTransaction()
|
this.connection.endTransaction()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun delete_trkpt(trkpt: Trkpt)
|
fun delete_trkpt(device_id: String, time: Long)
|
||||||
{
|
{
|
||||||
Log.i("VOUSSOIR", "Database.delete_trkpt")
|
Log.i("VOUSSOIR", "Database.delete_trkpt")
|
||||||
begin_transaction()
|
begin_transaction()
|
||||||
connection.delete("trkpt", "device_id = ? AND time = ?", arrayOf(trkpt.device_id, trkpt.time.toString()))
|
connection.delete("trkpt", "device_id = ? AND time = ?", arrayOf(device_id, time.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun delete_trkpt_start_end(device_id: String, start_time: Long, end_time: Long)
|
fun delete_trkpt_start_end(device_id: String, start_time: Long, end_time: Long)
|
||||||
|
|
@ -101,23 +101,9 @@ class Database(val trackbook: Trackbook)
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun select_trkpt_bounding_box(device_id: String?, north: Double, south: Double, east: Double, west: Double, max_accuracy: Float=Keys.DEFAULT_MAX_ACCURACY): Iterator<Trkpt>
|
fun select_trkpt_bounding_box(device_id: String, north: Double, south: Double, east: Double, west: Double, max_accuracy: Float=Keys.DEFAULT_MAX_ACCURACY): Iterator<Trkpt>
|
||||||
{
|
{
|
||||||
Log.i("VOUSSOIR", "Track.trkpt_generator: Querying points between $north, $south, $east, $west.")
|
Log.i("VOUSSOIR", "Track.trkpt_generator: Querying points between $north, $south, $east, $west.")
|
||||||
if (device_id == null)
|
|
||||||
{
|
|
||||||
return _trkpt_generator(this.connection.rawQuery(
|
|
||||||
"""
|
|
||||||
SELECT device_id, lat, lon, time, provider, ele, accuracy, sat
|
|
||||||
FROM trkpt
|
|
||||||
WHERE lat >= ? AND lat <= ? AND lon >= ? AND lon <= ? AND accuracy <= ?
|
|
||||||
ORDER BY time ASC
|
|
||||||
""",
|
|
||||||
arrayOf(south.toString(), north.toString(), west.toString(), east.toString(), max_accuracy.toString())
|
|
||||||
))
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return _trkpt_generator(this.connection.rawQuery(
|
return _trkpt_generator(this.connection.rawQuery(
|
||||||
"""
|
"""
|
||||||
SELECT device_id, lat, lon, time, provider, ele, accuracy, sat
|
SELECT device_id, lat, lon, time, provider, ele, accuracy, sat
|
||||||
|
|
@ -128,7 +114,6 @@ class Database(val trackbook: Trackbook)
|
||||||
arrayOf(device_id, south.toString(), north.toString(), west.toString(), east.toString(), max_accuracy.toString())
|
arrayOf(device_id, south.toString(), north.toString(), west.toString(), east.toString(), max_accuracy.toString())
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fun _trkpt_generator(cursor: Cursor) = iterator<Trkpt>
|
fun _trkpt_generator(cursor: Cursor) = iterator<Trkpt>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -79,10 +79,6 @@ object Keys {
|
||||||
const val STATE_THEME_LIGHT_MODE: String = "stateLightMode"
|
const val STATE_THEME_LIGHT_MODE: String = "stateLightMode"
|
||||||
const val STATE_THEME_DARK_MODE: String = "stateDarkMode"
|
const val STATE_THEME_DARK_MODE: String = "stateDarkMode"
|
||||||
|
|
||||||
// Track view
|
|
||||||
const val SELECTION_MODE_STARTSTOP = 1
|
|
||||||
const val SELECTION_MODE_SPATIAL = 2
|
|
||||||
|
|
||||||
// dialog types
|
// dialog types
|
||||||
const val DIALOG_DELETE_TRACK: Int = 1
|
const val DIALOG_DELETE_TRACK: Int = 1
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,6 @@ class MainActivity: AppCompatActivity()
|
||||||
/* Overrides onCreate from AppCompatActivity */
|
/* Overrides onCreate from AppCompatActivity */
|
||||||
override fun onCreate(savedInstanceState: Bundle?)
|
override fun onCreate(savedInstanceState: Bundle?)
|
||||||
{
|
{
|
||||||
Log.i("VOUSSOIR", "MainActivity.onCreate")
|
|
||||||
trackbook = (applicationContext as Trackbook)
|
trackbook = (applicationContext as Trackbook)
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
request_permissions(this)
|
request_permissions(this)
|
||||||
|
|
@ -126,7 +125,6 @@ class MainActivity: AppCompatActivity()
|
||||||
/* Overrides onDestroy from AppCompatActivity */
|
/* Overrides onDestroy from AppCompatActivity */
|
||||||
override fun onDestroy()
|
override fun onDestroy()
|
||||||
{
|
{
|
||||||
Log.i("VOUSSOIR", "MainActivity.onDestroy")
|
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
// unregister listener for changes in shared preferences
|
// unregister listener for changes in shared preferences
|
||||||
PreferencesHelper.unregisterPreferenceChangeListener(sharedPreferenceChangeListener)
|
PreferencesHelper.unregisterPreferenceChangeListener(sharedPreferenceChangeListener)
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import org.osmdroid.events.MapEventsReceiver
|
import org.osmdroid.events.MapEventsReceiver
|
||||||
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
|
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
|
||||||
import org.osmdroid.util.GeoPoint
|
import org.osmdroid.util.GeoPoint
|
||||||
|
|
@ -56,16 +57,15 @@ class MapFragment : Fragment()
|
||||||
{
|
{
|
||||||
private lateinit var trackbook: Trackbook
|
private lateinit var trackbook: Trackbook
|
||||||
|
|
||||||
private var tracker_service_bound: Boolean = false
|
private var bound: Boolean = false
|
||||||
private var tracker_service: TrackerService? = null
|
|
||||||
|
|
||||||
val handler: Handler = Handler(Looper.getMainLooper())
|
val handler: Handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
var continuous_auto_center: Boolean = true
|
var continuous_auto_center: Boolean = true
|
||||||
|
private var trackerService: TrackerService? = null
|
||||||
|
private lateinit var database_changed_listener: DatabaseChangedListener
|
||||||
var show_debug: Boolean = false
|
var show_debug: Boolean = false
|
||||||
|
|
||||||
private lateinit var database_changed_listener: DatabaseChangedListener
|
var thismapfragment: MapFragment? = null
|
||||||
|
|
||||||
lateinit var rootView: View
|
lateinit var rootView: View
|
||||||
private lateinit var mapView: MapView
|
private lateinit var mapView: MapView
|
||||||
lateinit var mainButton: ExtendedFloatingActionButton
|
lateinit var mainButton: ExtendedFloatingActionButton
|
||||||
|
|
@ -77,12 +77,14 @@ class MapFragment : Fragment()
|
||||||
private var current_track_overlay: Polyline? = null
|
private var current_track_overlay: Polyline? = null
|
||||||
private var current_position_overlays = ArrayList<Overlay>()
|
private var current_position_overlays = ArrayList<Overlay>()
|
||||||
private var homepoints_overlays = ArrayList<Overlay>()
|
private var homepoints_overlays = ArrayList<Overlay>()
|
||||||
|
private lateinit var locationErrorBar: Snackbar
|
||||||
|
|
||||||
/* 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)
|
||||||
|
thismapfragment = this
|
||||||
this.trackbook = (requireContext().applicationContext as Trackbook)
|
this.trackbook = (requireContext().applicationContext as Trackbook)
|
||||||
database_changed_listener = object: DatabaseChangedListener
|
database_changed_listener = object: DatabaseChangedListener
|
||||||
{
|
{
|
||||||
|
|
@ -114,6 +116,7 @@ class MapFragment : Fragment()
|
||||||
zoom_out_button = rootView.findViewById(R.id.zoom_out_button)
|
zoom_out_button = rootView.findViewById(R.id.zoom_out_button)
|
||||||
map_current_time = rootView.findViewById(R.id.map_current_time)
|
map_current_time = rootView.findViewById(R.id.map_current_time)
|
||||||
mainButton = rootView.findViewById(R.id.main_button)
|
mainButton = rootView.findViewById(R.id.main_button)
|
||||||
|
locationErrorBar = Snackbar.make(mapView, String(), Snackbar.LENGTH_INDEFINITE)
|
||||||
|
|
||||||
mapView.setOnLongClickListener{
|
mapView.setOnLongClickListener{
|
||||||
Log.i("VOUSSOIR", "mapview longpress")
|
Log.i("VOUSSOIR", "mapview longpress")
|
||||||
|
|
@ -195,7 +198,7 @@ class MapFragment : Fragment()
|
||||||
}
|
}
|
||||||
|
|
||||||
mainButton.setOnClickListener {
|
mainButton.setOnClickListener {
|
||||||
val tracker = tracker_service
|
val tracker = trackerService
|
||||||
if (tracker == null)
|
if (tracker == null)
|
||||||
{
|
{
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
|
|
@ -211,7 +214,7 @@ class MapFragment : Fragment()
|
||||||
handler.postDelayed(redraw_runnable, 0)
|
handler.postDelayed(redraw_runnable, 0)
|
||||||
}
|
}
|
||||||
currentLocationButton.setOnClickListener {
|
currentLocationButton.setOnClickListener {
|
||||||
val tracker = tracker_service
|
val tracker = trackerService
|
||||||
if (tracker == null)
|
if (tracker == null)
|
||||||
{
|
{
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
|
|
@ -237,7 +240,13 @@ class MapFragment : Fragment()
|
||||||
{
|
{
|
||||||
Log.i("VOUSSOIR", "MapFragment.onStart")
|
Log.i("VOUSSOIR", "MapFragment.onStart")
|
||||||
super.onStart()
|
super.onStart()
|
||||||
activity?.bindService(Intent(activity, TrackerService::class.java), tracker_service_connection, Context.BIND_AUTO_CREATE)
|
// request location permission if denied
|
||||||
|
if (ContextCompat.checkSelfPermission(activity as Context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_DENIED)
|
||||||
|
{
|
||||||
|
requestLocationPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
|
||||||
|
}
|
||||||
|
// bind to TrackerService
|
||||||
|
activity?.bindService(Intent(activity, TrackerService::class.java), connection, Context.BIND_AUTO_CREATE)
|
||||||
handler.post(redraw_runnable)
|
handler.post(redraw_runnable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -261,13 +270,13 @@ class MapFragment : Fragment()
|
||||||
super.onPause()
|
super.onPause()
|
||||||
requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
requireActivity().window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
|
|
||||||
val tracker = tracker_service
|
val tracker = trackerService
|
||||||
if (tracker == null)
|
if (tracker == null)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
saveBestLocationState(tracker.currentBestLocation)
|
saveBestLocationState(tracker.currentBestLocation)
|
||||||
if (tracker_service_bound && (tracker.tracking_state == Keys.STATE_MAPVIEW || tracker.tracking_state == Keys.STATE_STOP))
|
if (bound && (tracker.tracking_state == Keys.STATE_MAPVIEW || tracker.tracking_state == Keys.STATE_STOP))
|
||||||
{
|
{
|
||||||
tracker.remove_gps_location_listener()
|
tracker.remove_gps_location_listener()
|
||||||
tracker.remove_network_location_listener()
|
tracker.remove_network_location_listener()
|
||||||
|
|
@ -281,9 +290,9 @@ class MapFragment : Fragment()
|
||||||
{
|
{
|
||||||
super.onStop()
|
super.onStop()
|
||||||
// unbind from TrackerService
|
// unbind from TrackerService
|
||||||
if (tracker_service_bound)
|
if (bound)
|
||||||
{
|
{
|
||||||
activity?.unbindService(tracker_service_connection)
|
activity?.unbindService(connection)
|
||||||
handleServiceUnbind()
|
handleServiceUnbind()
|
||||||
}
|
}
|
||||||
handler.removeCallbacks(redraw_runnable)
|
handler.removeCallbacks(redraw_runnable)
|
||||||
|
|
@ -308,6 +317,24 @@ class MapFragment : Fragment()
|
||||||
handler.removeCallbacks(redraw_runnable)
|
handler.removeCallbacks(redraw_runnable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val requestLocationPermissionLauncher = registerForActivityResult(RequestPermission()) { isGranted: Boolean ->
|
||||||
|
if (isGranted)
|
||||||
|
{
|
||||||
|
// permission was granted - re-bind service
|
||||||
|
activity?.unbindService(connection)
|
||||||
|
activity?.bindService(Intent(activity, TrackerService::class.java), connection, Context.BIND_AUTO_CREATE)
|
||||||
|
Log.i("VOUSSOIR", "Request result: Location permission has been granted.")
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// permission denied - unbind service
|
||||||
|
activity?.unbindService(connection)
|
||||||
|
}
|
||||||
|
val gpsProviderActive = if (trackerService == null) false else trackerService!!.gpsProviderActive
|
||||||
|
val networkProviderActive = if (trackerService == null) false else trackerService!!.networkProviderActive
|
||||||
|
toggleLocationErrorBar(gpsProviderActive, networkProviderActive)
|
||||||
|
}
|
||||||
|
|
||||||
private fun startTracking()
|
private fun startTracking()
|
||||||
{
|
{
|
||||||
// start service via intent so that it keeps running after unbind
|
// start service via intent so that it keeps running after unbind
|
||||||
|
|
@ -321,9 +348,9 @@ class MapFragment : Fragment()
|
||||||
{
|
{
|
||||||
activity?.startService(intent)
|
activity?.startService(intent)
|
||||||
}
|
}
|
||||||
if (tracker_service != null)
|
if (trackerService != null)
|
||||||
{
|
{
|
||||||
tracker_service!!.state_full_recording()
|
trackerService!!.state_full_recording()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,7 +358,7 @@ class MapFragment : Fragment()
|
||||||
/* Handles state when service is being unbound */
|
/* Handles state when service is being unbound */
|
||||||
private fun handleServiceUnbind()
|
private fun handleServiceUnbind()
|
||||||
{
|
{
|
||||||
tracker_service_bound = false
|
bound = false
|
||||||
// unregister listener for changes in shared preferences
|
// unregister listener for changes in shared preferences
|
||||||
PreferencesHelper.unregisterPreferenceChangeListener(sharedPreferenceChangeListener)
|
PreferencesHelper.unregisterPreferenceChangeListener(sharedPreferenceChangeListener)
|
||||||
}
|
}
|
||||||
|
|
@ -370,11 +397,12 @@ class MapFragment : Fragment()
|
||||||
current_position_overlays.clear()
|
current_position_overlays.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mark current position on map */
|
||||||
fun create_current_position_overlays()
|
fun create_current_position_overlays()
|
||||||
{
|
{
|
||||||
clear_current_position_overlays()
|
clear_current_position_overlays()
|
||||||
|
|
||||||
val tracker = tracker_service
|
val tracker = trackerService
|
||||||
if (tracker == null)
|
if (tracker == null)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
|
|
@ -551,7 +579,7 @@ class MapFragment : Fragment()
|
||||||
|
|
||||||
fun update_main_button()
|
fun update_main_button()
|
||||||
{
|
{
|
||||||
val tracker = tracker_service
|
val tracker = trackerService
|
||||||
mainButton.isEnabled = trackbook.database.ready
|
mainButton.isEnabled = trackbook.database.ready
|
||||||
currentLocationButton.isVisible = true
|
currentLocationButton.isVisible = true
|
||||||
if (! trackbook.database.ready)
|
if (! trackbook.database.ready)
|
||||||
|
|
@ -573,7 +601,27 @@ class MapFragment : Fragment()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val tracker_service_connection = object : ServiceConnection {
|
fun toggleLocationErrorBar(gpsProviderActive: Boolean, networkProviderActive: Boolean)
|
||||||
|
{
|
||||||
|
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_DENIED)
|
||||||
|
{
|
||||||
|
// CASE: Location permission not granted
|
||||||
|
locationErrorBar.setText(R.string.snackbar_message_location_permission_denied)
|
||||||
|
if (!locationErrorBar.isShown) locationErrorBar.show()
|
||||||
|
}
|
||||||
|
else if (!gpsProviderActive && !networkProviderActive)
|
||||||
|
{
|
||||||
|
// CASE: Location setting is off
|
||||||
|
locationErrorBar.setText(R.string.snackbar_message_location_offline)
|
||||||
|
if (!locationErrorBar.isShown) locationErrorBar.show()
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (locationErrorBar.isShown) locationErrorBar.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val connection = object : ServiceConnection {
|
||||||
override fun onServiceConnected(className: ComponentName, service: IBinder)
|
override fun onServiceConnected(className: ComponentName, service: IBinder)
|
||||||
{
|
{
|
||||||
// get reference to tracker service]
|
// get reference to tracker service]
|
||||||
|
|
@ -582,8 +630,8 @@ class MapFragment : Fragment()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tracker_service_bound = true
|
bound = true
|
||||||
tracker_service = serviceref
|
trackerService = serviceref
|
||||||
// get state of tracking and update button if necessary
|
// get state of tracking and update button if necessary
|
||||||
redraw()
|
redraw()
|
||||||
// register listener for changes in shared preferences
|
// register listener for changes in shared preferences
|
||||||
|
|
@ -600,7 +648,7 @@ class MapFragment : Fragment()
|
||||||
{
|
{
|
||||||
// Log.i("VOUSSOIR", "MapFragment.redraw")
|
// Log.i("VOUSSOIR", "MapFragment.redraw")
|
||||||
update_main_button()
|
update_main_button()
|
||||||
val tracker = tracker_service
|
val tracker = trackerService
|
||||||
if (tracker == null)
|
if (tracker == null)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
|
|
@ -645,7 +693,7 @@ class MapFragment : Fragment()
|
||||||
|
|
||||||
fun state_name(): String
|
fun state_name(): String
|
||||||
{
|
{
|
||||||
val tracker = tracker_service
|
val tracker = trackerService
|
||||||
if (tracker == null)
|
if (tracker == null)
|
||||||
{
|
{
|
||||||
return "null"
|
return "null"
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import java.util.*
|
||||||
|
|
||||||
data class Track (
|
data class Track (
|
||||||
val database: Database,
|
val database: Database,
|
||||||
var device_id: String,
|
val device_id: String,
|
||||||
var name: String = "",
|
var name: String = "",
|
||||||
var _start_time: Long = 0L,
|
var _start_time: Long = 0L,
|
||||||
var _end_time: Long = 0L,
|
var _end_time: Long = 0L,
|
||||||
|
|
|
||||||
|
|
@ -21,17 +21,12 @@
|
||||||
package net.voussoir.trkpt
|
package net.voussoir.trkpt
|
||||||
|
|
||||||
import YesNoDialog
|
import YesNoDialog
|
||||||
import android.Manifest
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.graphics.Color
|
|
||||||
import android.graphics.Paint
|
import android.graphics.Paint
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
import android.location.LocationListener
|
|
||||||
import android.location.LocationManager
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
|
|
@ -60,7 +55,10 @@ import org.osmdroid.events.ZoomEvent
|
||||||
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.*
|
import org.osmdroid.views.overlay.MapEventsOverlay
|
||||||
|
import org.osmdroid.views.overlay.Marker
|
||||||
|
import org.osmdroid.views.overlay.Polyline
|
||||||
|
import org.osmdroid.views.overlay.TilesOverlay
|
||||||
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
|
||||||
|
|
@ -73,7 +71,7 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
|
|
||||||
lateinit var rootView: View
|
lateinit var rootView: View
|
||||||
lateinit var save_track_button: ImageButton
|
lateinit var save_track_button: ImageButton
|
||||||
lateinit var delete_whole_track_button: ImageButton
|
lateinit var deleteButton: ImageButton
|
||||||
lateinit var zoom_in_button: FloatingActionButton
|
lateinit var zoom_in_button: FloatingActionButton
|
||||||
lateinit var zoom_out_button: FloatingActionButton
|
lateinit var zoom_out_button: FloatingActionButton
|
||||||
lateinit var trackNameView: MaterialTextView
|
lateinit var trackNameView: MaterialTextView
|
||||||
|
|
@ -95,8 +93,6 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
var ready_to_straighten: Boolean = false
|
var ready_to_straighten: Boolean = false
|
||||||
var track_query_start_time_previous: Int = 0
|
var track_query_start_time_previous: Int = 0
|
||||||
var track_query_end_time_previous: Int = 0
|
var track_query_end_time_previous: Int = 0
|
||||||
var selection_mode: Int = Keys.SELECTION_MODE_STARTSTOP
|
|
||||||
|
|
||||||
private lateinit var mapView: MapView
|
private lateinit var mapView: MapView
|
||||||
private lateinit var controller: IMapController
|
private lateinit var controller: IMapController
|
||||||
private lateinit var statisticsSheetBehavior: BottomSheetBehavior<View>
|
private lateinit var statisticsSheetBehavior: BottomSheetBehavior<View>
|
||||||
|
|
@ -119,7 +115,6 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
private lateinit var track_segment_overlays: ArrayDeque<Polyline>
|
private lateinit var track_segment_overlays: ArrayDeque<Polyline>
|
||||||
private var track_geopoints: MutableList<IGeoPoint> = mutableListOf()
|
private var track_geopoints: MutableList<IGeoPoint> = mutableListOf()
|
||||||
private var track_points_overlay: SimpleFastPointOverlay? = null
|
private var track_points_overlay: SimpleFastPointOverlay? = null
|
||||||
private var current_position_overlays = ArrayList<Overlay>()
|
|
||||||
// private lateinit var trkpt_infowindow: InfoWindow
|
// private lateinit var trkpt_infowindow: InfoWindow
|
||||||
private var useImperialUnits: Boolean = false
|
private var useImperialUnits: Boolean = false
|
||||||
private val handler: Handler = Handler(Looper.getMainLooper())
|
private val handler: Handler = Handler(Looper.getMainLooper())
|
||||||
|
|
@ -128,10 +123,6 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
var selected_trkpt: Trkpt? = null
|
var selected_trkpt: Trkpt? = null
|
||||||
lateinit var selected_trkpt_marker: Marker
|
lateinit var selected_trkpt_marker: Marker
|
||||||
|
|
||||||
private lateinit var locationManager: LocationManager
|
|
||||||
private lateinit var gpsLocationListener: LocationListener
|
|
||||||
private var gpslistenerregistered = false
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?)
|
override fun onCreate(savedInstanceState: Bundle?)
|
||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
@ -165,12 +156,10 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
end_time=requested_end_time,
|
end_time=requested_end_time,
|
||||||
max_accuracy=PreferencesHelper.load_max_accuracy(),
|
max_accuracy=PreferencesHelper.load_max_accuracy(),
|
||||||
))
|
))
|
||||||
selection_mode = Keys.SELECTION_MODE_STARTSTOP
|
|
||||||
|
|
||||||
rootView = inflater.inflate(R.layout.fragment_track, container, false)
|
rootView = inflater.inflate(R.layout.fragment_track, container, false)
|
||||||
mapView = rootView.findViewById(R.id.map)
|
mapView = rootView.findViewById(R.id.map)
|
||||||
save_track_button = rootView.findViewById(R.id.save_button)
|
save_track_button = rootView.findViewById(R.id.save_button)
|
||||||
delete_whole_track_button = rootView.findViewById(R.id.delete_button)
|
deleteButton = rootView.findViewById(R.id.delete_button)
|
||||||
zoom_in_button = rootView.findViewById(R.id.zoom_in_button)
|
zoom_in_button = rootView.findViewById(R.id.zoom_in_button)
|
||||||
zoom_out_button = rootView.findViewById(R.id.zoom_out_button)
|
zoom_out_button = rootView.findViewById(R.id.zoom_out_button)
|
||||||
trackNameView = rootView.findViewById(R.id.statistics_track_name_headline)
|
trackNameView = rootView.findViewById(R.id.statistics_track_name_headline)
|
||||||
|
|
@ -189,20 +178,6 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
}
|
}
|
||||||
controller.setZoom(Keys.DEFAULT_ZOOM_LEVEL)
|
controller.setZoom(Keys.DEFAULT_ZOOM_LEVEL)
|
||||||
|
|
||||||
val has_permission: Boolean = ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
|
||||||
if (has_permission)
|
|
||||||
{
|
|
||||||
locationManager = requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
|
||||||
gpsLocationListener = createLocationListener()
|
|
||||||
locationManager.requestLocationUpdates(
|
|
||||||
LocationManager.GPS_PROVIDER,
|
|
||||||
0,
|
|
||||||
0f,
|
|
||||||
gpsLocationListener,
|
|
||||||
)
|
|
||||||
gpslistenerregistered = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// trkpt_infowindow = MarkerInfoWindow(R.layout.trkpt_infowindow, mapView)
|
// trkpt_infowindow = MarkerInfoWindow(R.layout.trkpt_infowindow, mapView)
|
||||||
|
|
||||||
statisticsSheet = rootView.findViewById(R.id.statistics_sheet)
|
statisticsSheet = rootView.findViewById(R.id.statistics_sheet)
|
||||||
|
|
@ -296,7 +271,7 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
Log.i("VOUSSOIR", selected.rendered_by_polyline?.actualPoints?.size.toString())
|
Log.i("VOUSSOIR", selected.rendered_by_polyline?.actualPoints?.size.toString())
|
||||||
selected.rendered_by_polyline?.setPoints(ArrayList(selected.rendered_by_polyline?.actualPoints))
|
selected.rendered_by_polyline?.setPoints(ArrayList(selected.rendered_by_polyline?.actualPoints))
|
||||||
Log.i("VOUSSOIR", selected.rendered_by_polyline?.actualPoints?.size.toString())
|
Log.i("VOUSSOIR", selected.rendered_by_polyline?.actualPoints?.size.toString())
|
||||||
trackbook.database.delete_trkpt(selected)
|
trackbook.database.delete_trkpt(selected.device_id, selected.time)
|
||||||
trackbook.database.commit()
|
trackbook.database.commit()
|
||||||
deselect_trkpt()
|
deselect_trkpt()
|
||||||
mapView.invalidate()
|
mapView.invalidate()
|
||||||
|
|
@ -316,7 +291,6 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
end_time=track.trkpts.last().time,
|
end_time=track.trkpts.last().time,
|
||||||
max_accuracy=PreferencesHelper.load_max_accuracy(),
|
max_accuracy=PreferencesHelper.load_max_accuracy(),
|
||||||
))
|
))
|
||||||
selection_mode = Keys.SELECTION_MODE_STARTSTOP
|
|
||||||
deselect_trkpt()
|
deselect_trkpt()
|
||||||
render_track()
|
render_track()
|
||||||
}
|
}
|
||||||
|
|
@ -335,7 +309,6 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
end_time=selected.time,
|
end_time=selected.time,
|
||||||
max_accuracy=PreferencesHelper.load_max_accuracy(),
|
max_accuracy=PreferencesHelper.load_max_accuracy(),
|
||||||
))
|
))
|
||||||
selection_mode = Keys.SELECTION_MODE_STARTSTOP
|
|
||||||
deselect_trkpt()
|
deselect_trkpt()
|
||||||
render_track()
|
render_track()
|
||||||
}
|
}
|
||||||
|
|
@ -350,14 +323,12 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
val polyline = selected.rendered_by_polyline
|
val polyline = selected.rendered_by_polyline
|
||||||
if (polyline != null)
|
if (polyline != null)
|
||||||
{
|
{
|
||||||
track.device_id = selected.device_id
|
|
||||||
track.load_trkpts(trackbook.database.select_trkpt_start_end(
|
track.load_trkpts(trackbook.database.select_trkpt_start_end(
|
||||||
selected.device_id,
|
track.device_id,
|
||||||
start_time=(polyline.actualPoints.first() as Trkpt).time,
|
start_time=(polyline.actualPoints.first() as Trkpt).time,
|
||||||
end_time=(polyline.actualPoints.last() as Trkpt).time,
|
end_time=(polyline.actualPoints.last() as Trkpt).time,
|
||||||
max_accuracy=PreferencesHelper.load_max_accuracy(),
|
max_accuracy=PreferencesHelper.load_max_accuracy(),
|
||||||
))
|
))
|
||||||
selection_mode = Keys.SELECTION_MODE_STARTSTOP
|
|
||||||
|
|
||||||
track.expand_to_trkseg_bounds()
|
track.expand_to_trkseg_bounds()
|
||||||
|
|
||||||
|
|
@ -371,14 +342,13 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
when_was_i_here_button.setOnClickListener {
|
when_was_i_here_button.setOnClickListener {
|
||||||
Log.i("VOUSSOIR", "when_was_i_here_button.")
|
Log.i("VOUSSOIR", "when_was_i_here_button.")
|
||||||
track.load_trkpts(trackbook.database.select_trkpt_bounding_box(
|
track.load_trkpts(trackbook.database.select_trkpt_bounding_box(
|
||||||
device_id=null,
|
device_id=track.device_id,
|
||||||
north=mapView.boundingBox.actualNorth,
|
north=mapView.boundingBox.actualNorth,
|
||||||
south=mapView.boundingBox.actualSouth,
|
south=mapView.boundingBox.actualSouth,
|
||||||
east=mapView.boundingBox.lonEast,
|
east=mapView.boundingBox.lonEast,
|
||||||
west=mapView.boundingBox.lonWest,
|
west=mapView.boundingBox.lonWest,
|
||||||
max_accuracy=PreferencesHelper.load_max_accuracy(),
|
max_accuracy=PreferencesHelper.load_max_accuracy(),
|
||||||
))
|
))
|
||||||
selection_mode = Keys.SELECTION_MODE_SPATIAL
|
|
||||||
set_datetimes_from_track()
|
set_datetimes_from_track()
|
||||||
render_track()
|
render_track()
|
||||||
}
|
}
|
||||||
|
|
@ -444,7 +414,7 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
dialog.show()
|
dialog.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
delete_whole_track_button.setOnClickListener {
|
deleteButton.setOnClickListener {
|
||||||
val dialogMessage = "${getString(R.string.dialog_yes_no_message_delete_recording)}\n\n${track.trkpts.size} trackpoints"
|
val dialogMessage = "${getString(R.string.dialog_yes_no_message_delete_recording)}\n\n${track.trkpts.size} trackpoints"
|
||||||
YesNoDialog(this@TrackFragment as YesNoDialog.YesNoDialogListener).show(
|
YesNoDialog(this@TrackFragment as YesNoDialog.YesNoDialogListener).show(
|
||||||
context = activity as Context,
|
context = activity as Context,
|
||||||
|
|
@ -498,78 +468,12 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
return rootView
|
return rootView
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView()
|
|
||||||
{
|
|
||||||
super.onDestroyView()
|
|
||||||
if (gpslistenerregistered)
|
|
||||||
{
|
|
||||||
locationManager.removeUpdates(gpsLocationListener)
|
|
||||||
gpslistenerregistered = 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()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun create_current_position_overlays(location: Location)
|
|
||||||
{
|
|
||||||
clear_current_position_overlays()
|
|
||||||
|
|
||||||
val newMarker = ContextCompat.getDrawable(requireContext(), R.drawable.ic_marker_location_blue_24dp)!!
|
|
||||||
val fillcolor = Color.argb(64, 60, 152, 219)
|
|
||||||
|
|
||||||
val current_location_radius = Polygon()
|
|
||||||
current_location_radius.points = Polygon.pointsAsCircle(
|
|
||||||
GeoPoint(location.latitude, location.longitude),
|
|
||||||
location.accuracy.toDouble()
|
|
||||||
)
|
|
||||||
current_location_radius.fillPaint.color = fillcolor
|
|
||||||
current_location_radius.outlinePaint.color = Color.argb(0, 0, 0, 0)
|
|
||||||
current_position_overlays.add(current_location_radius)
|
|
||||||
|
|
||||||
val overlayItems: java.util.ArrayList<OverlayItem> = java.util.ArrayList<OverlayItem>()
|
|
||||||
val overlayItem: OverlayItem = createOverlayItem(
|
|
||||||
location.latitude,
|
|
||||||
location.longitude,
|
|
||||||
title="Current location",
|
|
||||||
description="Current location",
|
|
||||||
)
|
|
||||||
overlayItem.setMarker(newMarker)
|
|
||||||
overlayItems.add(overlayItem)
|
|
||||||
current_position_overlays.add(createOverlay(requireContext(), overlayItems))
|
|
||||||
|
|
||||||
for (ov in current_position_overlays)
|
|
||||||
{
|
|
||||||
mapView.overlays.add(ov)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Overrides onResume from Fragment */
|
/* Overrides onResume from Fragment */
|
||||||
override fun onResume()
|
override fun onResume()
|
||||||
{
|
{
|
||||||
super.onResume()
|
super.onResume()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createLocationListener(): LocationListener
|
|
||||||
{
|
|
||||||
return object : LocationListener
|
|
||||||
{
|
|
||||||
override fun onLocationChanged(location: Location)
|
|
||||||
{
|
|
||||||
create_current_position_overlays(location)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun select_trkpt(trkpt: Trkpt)
|
fun select_trkpt(trkpt: Trkpt)
|
||||||
{
|
{
|
||||||
selected_trkpt = trkpt
|
selected_trkpt = trkpt
|
||||||
|
|
@ -753,11 +657,6 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
{
|
{
|
||||||
create_start_end_markers(requireContext(), mapView, pl.actualPoints.first() as Trkpt, pl.actualPoints.last() as Trkpt)
|
create_start_end_markers(requireContext(), mapView, pl.actualPoints.first() as Trkpt, pl.actualPoints.last() as Trkpt)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ov in current_position_overlays)
|
|
||||||
{
|
|
||||||
mapView.overlays.add(ov)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun new_track_segment_overlay(): Polyline
|
fun new_track_segment_overlay(): Polyline
|
||||||
|
|
@ -931,7 +830,6 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
end_time=get_datetime(track_query_end_date, track_query_end_time, seconds=59).time,
|
end_time=get_datetime(track_query_end_date, track_query_end_time, seconds=59).time,
|
||||||
max_accuracy=PreferencesHelper.load_max_accuracy(),
|
max_accuracy=PreferencesHelper.load_max_accuracy(),
|
||||||
))
|
))
|
||||||
selection_mode = Keys.SELECTION_MODE_STARTSTOP
|
|
||||||
Log.i("VOUSSOIR", "TrackFragment.requery_and_render: Reloaded ${track.trkpts.size} trkpts.")
|
Log.i("VOUSSOIR", "TrackFragment.requery_and_render: Reloaded ${track.trkpts.size} trkpts.")
|
||||||
render_track()
|
render_track()
|
||||||
}
|
}
|
||||||
|
|
@ -964,8 +862,6 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
override fun onYesNoDialog(type: Int, dialogResult: Boolean, payload: Int, payloadString: String)
|
override fun onYesNoDialog(type: Int, dialogResult: Boolean, payload: Int, payloadString: String)
|
||||||
{
|
{
|
||||||
if (type == Keys.DIALOG_DELETE_TRACK && dialogResult && track.trkpts.isNotEmpty())
|
if (type == Keys.DIALOG_DELETE_TRACK && dialogResult && track.trkpts.isNotEmpty())
|
||||||
{
|
|
||||||
if (selection_mode == Keys.SELECTION_MODE_STARTSTOP)
|
|
||||||
{
|
{
|
||||||
trackbook.database.delete_trkpt_start_end(
|
trackbook.database.delete_trkpt_start_end(
|
||||||
track.device_id,
|
track.device_id,
|
||||||
|
|
@ -976,21 +872,6 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
||||||
handler.removeCallbacks(requery_and_render)
|
handler.removeCallbacks(requery_and_render)
|
||||||
handler.postDelayed(requery_and_render, RERENDER_DELAY)
|
handler.postDelayed(requery_and_render, RERENDER_DELAY)
|
||||||
}
|
}
|
||||||
else if (selection_mode == Keys.SELECTION_MODE_SPATIAL)
|
|
||||||
{
|
|
||||||
// If the user clicked the "when was I here" button to select an area of points, and
|
|
||||||
// then presses the Track delete button, we don't want to delete all points between
|
|
||||||
// the earliest start and latest stop -- we just want to delete the points that are
|
|
||||||
// shown on screen.
|
|
||||||
for (trkpt in track.trkpts)
|
|
||||||
{
|
|
||||||
trackbook.database.delete_trkpt(trkpt)
|
|
||||||
}
|
|
||||||
trackbook.database.commit()
|
|
||||||
handler.removeCallbacks(requery_and_render)
|
|
||||||
handler.postDelayed(requery_and_render, RERENDER_DELAY)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opens up a file picker to select the save location */
|
/* Opens up a file picker to select the save location */
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue