Rewrite TrackerService to be more like a state machine.
This commit is contained in:
parent
2e5be6a4e4
commit
3710755bc1
11 changed files with 280 additions and 332 deletions
|
@ -21,7 +21,7 @@ The goal of this fork is to make 24/7 recording easier. I want to be able to run
|
|||
|
||||
trkpt has three states of power management. The states transition like this:
|
||||
|
||||
1. **FULL POWER**: receives location updates as fast as Android provides them. A wakelock is used to prevent doze.
|
||||
1. **FULL POWER**: receives location updates as fast as Android provides them. A wakelock is used to resist doze (though I think some devices will doze anyway because they do not respect the user).
|
||||
|
||||
Stay near homepoint for a few minutes → Sleep
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ android {
|
|||
applicationId 'net.voussoir.trkpt'
|
||||
minSdkVersion 25
|
||||
targetSdk 32
|
||||
versionCode 54
|
||||
versionName '1.0.3'
|
||||
versionCode 55
|
||||
versionName '1.1.0'
|
||||
resConfigs "en", "da", "de", "fr", "hr", "id", "it", "ja", "nb-rNO", "nl", "pl", "pt-rBR", "ru", "sv", "tr", "zh-rCN"
|
||||
}
|
||||
|
||||
|
|
|
@ -53,18 +53,6 @@
|
|||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<!-- TRACKING TOGGLE SERVICE SYSTEM QUICK SETTINGS -->
|
||||
<service
|
||||
android:name="net.voussoir.trkpt.TrackingToggleTileService"
|
||||
android:label="@string/quick_settings_tile_title_default"
|
||||
android:icon="@drawable/ic_notification_icon_small_24dp"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<!-- FILE PROVIDER GPX -->
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
|
|
|
@ -40,7 +40,6 @@ object Keys {
|
|||
|
||||
// args
|
||||
const val ARG_TRACK_TITLE: String = "ArgTrackTitle"
|
||||
const val ARG_TRACK_ID: String = "ArgTrackID"
|
||||
const val ARG_TRACK_DEVICE_ID: String = "ArgTrackDeviceID"
|
||||
const val ARG_TRACK_START_TIME: String = "ArgTrackStartTime"
|
||||
const val ARG_TRACK_STOP_TIME: String = "ArgTrackStopTime"
|
||||
|
@ -67,12 +66,15 @@ object Keys {
|
|||
const val PREF_MAX_ACCURACY: String = "prefMaxAccuracy"
|
||||
|
||||
// states
|
||||
const val STATE_TRACKING_STOPPED: Int = 0
|
||||
const val STATE_TRACKING_ACTIVE: Int = 1
|
||||
const val STATE_STOP: Int = 0
|
||||
const val STATE_FULL_RECORDING: Int = 1
|
||||
const val STATE_ARRIVED_AT_HOME: Int = 2
|
||||
const val STATE_SLEEP: Int = 3
|
||||
const val STATE_DEAD: Int = 4
|
||||
const val STATE_MAPVIEW: Int = 5
|
||||
const val LOCATION_INTERVAL_FULL_POWER: Long = 0
|
||||
const val LOCATION_INTERVAL_SLEEP: Long = ONE_MINUTE_IN_MILLISECONDS
|
||||
const val LOCATION_INTERVAL_DEAD: Long = -1
|
||||
const val LOCATION_INTERVAL_STOP: Long = -2
|
||||
const val LOCATION_INTERVAL_STOP: Long = -1
|
||||
const val STATE_THEME_FOLLOW_SYSTEM: String = "stateFollowSystem"
|
||||
const val STATE_THEME_LIGHT_MODE: String = "stateLightMode"
|
||||
const val STATE_THEME_DARK_MODE: String = "stateDarkMode"
|
||||
|
|
|
@ -203,9 +203,9 @@ class MapFragment : Fragment()
|
|||
{
|
||||
return@setOnClickListener
|
||||
}
|
||||
if (tracker.trackingState == Keys.STATE_TRACKING_ACTIVE)
|
||||
if (tracker.tracking_state != Keys.STATE_STOP && tracker.tracking_state != Keys.STATE_MAPVIEW)
|
||||
{
|
||||
tracker.stopTracking()
|
||||
tracker.state_mapview()
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -276,10 +276,10 @@ class MapFragment : Fragment()
|
|||
return
|
||||
}
|
||||
saveBestLocationState(tracker.currentBestLocation)
|
||||
if (bound && tracker.trackingState != Keys.STATE_TRACKING_ACTIVE)
|
||||
if (bound && (tracker.tracking_state == Keys.STATE_MAPVIEW || tracker.tracking_state == Keys.STATE_STOP))
|
||||
{
|
||||
tracker.removeGpsLocationListener()
|
||||
tracker.removeNetworkLocationListener()
|
||||
tracker.remove_gps_location_listener()
|
||||
tracker.remove_network_location_listener()
|
||||
tracker.trackbook.database.commit()
|
||||
}
|
||||
handler.removeCallbacks(redraw_runnable)
|
||||
|
@ -350,7 +350,7 @@ class MapFragment : Fragment()
|
|||
}
|
||||
if (trackerService != null)
|
||||
{
|
||||
trackerService!!.startTracking()
|
||||
trackerService!!.state_full_recording()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -413,19 +413,13 @@ class MapFragment : Fragment()
|
|||
val newMarker: Drawable
|
||||
val fillcolor: Int
|
||||
val description: String
|
||||
if (tracker.listeners_enabled_at == 0L)
|
||||
{
|
||||
fillcolor = Color.argb(64, 0, 0, 0)
|
||||
newMarker = ContextCompat.getDrawable(requireContext(), R.drawable.ic_skull_24dp)!!
|
||||
description = "No location listeners are enabled"
|
||||
}
|
||||
else if (tracker.trackingState == Keys.STATE_TRACKING_ACTIVE && tracker.location_interval == Keys.LOCATION_INTERVAL_DEAD)
|
||||
if (tracker.tracking_state == Keys.STATE_DEAD)
|
||||
{
|
||||
fillcolor = Color.argb(64, 0, 0, 0)
|
||||
newMarker = ContextCompat.getDrawable(requireContext(), R.drawable.ic_skull_24dp)!!
|
||||
description = "GPS is struggling; disabled until movement"
|
||||
}
|
||||
else if (tracker.trackingState == Keys.STATE_TRACKING_ACTIVE && tracker.location_interval == Keys.LOCATION_INTERVAL_SLEEP)
|
||||
else if (tracker.tracking_state == Keys.STATE_SLEEP)
|
||||
{
|
||||
fillcolor = Color.argb(64, 220, 61, 51)
|
||||
newMarker = ContextCompat.getDrawable(requireContext(), R.drawable.ic_sleep_24dp)!!
|
||||
|
@ -437,7 +431,7 @@ class MapFragment : Fragment()
|
|||
newMarker = ContextCompat.getDrawable(requireContext(), R.drawable.ic_marker_location_black_24dp)!!
|
||||
description = "GPS tracking at full power"
|
||||
}
|
||||
else if (tracker.trackingState == Keys.STATE_TRACKING_ACTIVE)
|
||||
else if (tracker.tracking_state == Keys.STATE_FULL_RECORDING || tracker.tracking_state == Keys.STATE_ARRIVED_AT_HOME)
|
||||
{
|
||||
fillcolor = Color.argb(64, 220, 61, 51)
|
||||
newMarker = ContextCompat.getDrawable(requireContext(), R.drawable.ic_marker_location_red_24dp)!!
|
||||
|
@ -591,13 +585,13 @@ class MapFragment : Fragment()
|
|||
mainButton.text = requireContext().getString(R.string.button_not_ready)
|
||||
mainButton.icon = null
|
||||
}
|
||||
else if (tracker == null || tracker.trackingState == Keys.STATE_TRACKING_STOPPED)
|
||||
else if (tracker == null || tracker.tracking_state == Keys.STATE_STOP || tracker.tracking_state == Keys.STATE_MAPVIEW)
|
||||
{
|
||||
mainButton.setIconResource(R.drawable.ic_fiber_manual_record_inactive_24dp)
|
||||
mainButton.text = requireContext().getString(R.string.button_start)
|
||||
mainButton.contentDescription = requireContext().getString(R.string.descr_button_start)
|
||||
}
|
||||
else if (tracker.trackingState == Keys.STATE_TRACKING_ACTIVE)
|
||||
else
|
||||
{
|
||||
mainButton.setIconResource(R.drawable.ic_fiber_manual_stop_24dp)
|
||||
mainButton.text = requireContext().getString(R.string.button_pause)
|
||||
|
@ -672,11 +666,13 @@ class MapFragment : Fragment()
|
|||
if (show_debug)
|
||||
{
|
||||
map_current_time.text = """
|
||||
state: ${state_name()}
|
||||
now: ${iso8601_local_noms(System.currentTimeMillis())}
|
||||
location: ${iso8601_local_noms(tracker.currentBestLocation.time)}
|
||||
listeners: ${iso8601_local_noms(tracker.listeners_enabled_at)}
|
||||
motion: ${iso8601_local_noms(tracker.last_significant_motion)}
|
||||
watchdog: ${iso8601_local_noms(tracker.last_watchdog)}
|
||||
home: ${iso8601_local_noms(tracker.arrived_at_home)}
|
||||
died: ${iso8601_local_noms(tracker.gave_up_at)}
|
||||
power: ${tracker.device_is_charging}
|
||||
wakelock: ${tracker.wakelock.isHeld}
|
||||
|
@ -690,6 +686,25 @@ class MapFragment : Fragment()
|
|||
mapView.invalidate()
|
||||
}
|
||||
|
||||
fun state_name(): String
|
||||
{
|
||||
val tracker = trackerService
|
||||
if (tracker == null)
|
||||
{
|
||||
return "null"
|
||||
}
|
||||
return when (tracker.tracking_state)
|
||||
{
|
||||
Keys.STATE_STOP -> "stop"
|
||||
Keys.STATE_FULL_RECORDING -> "recording"
|
||||
Keys.STATE_ARRIVED_AT_HOME -> "home"
|
||||
Keys.STATE_SLEEP -> "sleep"
|
||||
Keys.STATE_DEAD -> "dead"
|
||||
Keys.STATE_MAPVIEW -> "mapview"
|
||||
else -> tracker.tracking_state.toString()
|
||||
}
|
||||
}
|
||||
|
||||
val redraw_runnable: Runnable = object : Runnable
|
||||
{
|
||||
override fun run()
|
||||
|
|
|
@ -173,8 +173,8 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener
|
|||
mapView.zoomController.setVisibility(org.osmdroid.views.CustomZoomButtonsController.Visibility.NEVER)
|
||||
if (track.trkpts.size > 0)
|
||||
{
|
||||
val first = track.trkpts.first()
|
||||
controller.setCenter(GeoPoint(first.latitude, first.longitude))
|
||||
val last = track.trkpts.last()
|
||||
controller.setCenter(GeoPoint(last.latitude, last.longitude))
|
||||
}
|
||||
controller.setZoom(Keys.DEFAULT_ZOOM_LEVEL)
|
||||
|
||||
|
|
|
@ -43,20 +43,20 @@ class TrackerService: Service()
|
|||
lateinit var trackbook: Trackbook
|
||||
val handler: Handler = Handler(Looper.getMainLooper())
|
||||
|
||||
var trackingState: Int = Keys.STATE_TRACKING_STOPPED
|
||||
var tracking_state: Int = Keys.STATE_STOP
|
||||
var useImperial: Boolean = false
|
||||
var omitRests: Boolean = true
|
||||
var max_accuracy: Float = Keys.DEFAULT_MAX_ACCURACY
|
||||
var allow_sleep: Boolean = true
|
||||
var device_id: String = random_device_id()
|
||||
var currentBestLocation: Location = getDefaultLocation()
|
||||
var lastCommit: Long = 0
|
||||
var last_commit: Long = 0
|
||||
var foreground_started: Long = 0
|
||||
var listeners_enabled_at: Long = 0
|
||||
var last_significant_motion: Long = 0
|
||||
var last_watchdog: Long = 0
|
||||
var gave_up_at: Long = 0
|
||||
var arrived_at_home: Long = 0
|
||||
var location_interval: Long = 0
|
||||
val TIME_UNTIL_SLEEP: Long = 5 * Keys.ONE_MINUTE_IN_MILLISECONDS
|
||||
val TIME_UNTIL_DEAD: Long = 3 * Keys.ONE_MINUTE_IN_MILLISECONDS
|
||||
val WATCHDOG_INTERVAL: Long = 61 * Keys.ONE_SECOND_IN_MILLISECONDS
|
||||
|
@ -67,7 +67,7 @@ class TrackerService: Service()
|
|||
var bound: Boolean = false
|
||||
private val binder = TrackerServiceBinder(this)
|
||||
|
||||
private lateinit var notificationManager: NotificationManager
|
||||
private lateinit var notification_manager: NotificationManager
|
||||
private lateinit var notification_builder: NotificationCompat.Builder
|
||||
|
||||
private lateinit var locationManager: LocationManager
|
||||
|
@ -90,7 +90,7 @@ class TrackerService: Service()
|
|||
|
||||
lateinit var wakelock: PowerManager.WakeLock
|
||||
|
||||
private fun addGpsLocationListener(interval: Long): Boolean
|
||||
private fun add_gps_location_listener(interval: Long): Boolean
|
||||
{
|
||||
gpsLocationListenerRegistered = false
|
||||
gpsProviderActive = isGpsEnabled(locationManager)
|
||||
|
@ -118,7 +118,7 @@ class TrackerService: Service()
|
|||
return true
|
||||
}
|
||||
|
||||
private fun addNetworkLocationListener(interval: Long): Boolean
|
||||
private fun add_network_location_listener(interval: Long): Boolean
|
||||
{
|
||||
networkLocationListenerRegistered = false
|
||||
networkProviderActive = isNetworkEnabled(locationManager)
|
||||
|
@ -146,7 +146,7 @@ class TrackerService: Service()
|
|||
return true
|
||||
}
|
||||
|
||||
fun removeGpsLocationListener()
|
||||
fun remove_gps_location_listener()
|
||||
{
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
|
||||
{
|
||||
|
@ -160,7 +160,7 @@ class TrackerService: Service()
|
|||
}
|
||||
}
|
||||
|
||||
fun removeNetworkLocationListener()
|
||||
fun remove_network_location_listener()
|
||||
{
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
|
||||
{
|
||||
|
@ -174,67 +174,171 @@ class TrackerService: Service()
|
|||
}
|
||||
}
|
||||
|
||||
fun load_tracking_state()
|
||||
{
|
||||
tracking_state = PreferencesHelper.loadTrackingState()
|
||||
when (tracking_state)
|
||||
{
|
||||
Keys.STATE_STOP -> state_stop()
|
||||
Keys.STATE_MAPVIEW -> state_mapview()
|
||||
Keys.STATE_FULL_RECORDING -> state_full_recording()
|
||||
Keys.STATE_ARRIVED_AT_HOME -> state_arrived_at_home()
|
||||
Keys.STATE_SLEEP -> state_sleep()
|
||||
Keys.STATE_DEAD -> state_dead()
|
||||
}
|
||||
}
|
||||
|
||||
fun state_stop()
|
||||
{
|
||||
// This state is activated when the user intentionally stops the recording, or exits the
|
||||
// mapfragment without starting to record.
|
||||
Log.i("VOUSSOIR", "TrackerService.state_stop")
|
||||
tracking_state = Keys.STATE_STOP
|
||||
PreferencesHelper.saveTrackingState(tracking_state)
|
||||
reset_location_listeners(Keys.LOCATION_INTERVAL_STOP)
|
||||
trackbook.database.commit()
|
||||
recent_displacement_locations.clear()
|
||||
arrived_at_home = 0
|
||||
gave_up_at = 0
|
||||
if (foreground_started > 0)
|
||||
{
|
||||
stopForeground(STOP_FOREGROUND_DETACH)
|
||||
foreground_started = 0
|
||||
}
|
||||
stop_wakelock()
|
||||
displayNotification()
|
||||
}
|
||||
fun state_full_recording()
|
||||
{
|
||||
// This state is the only one that will record points into the database, and tracks location
|
||||
// at full power. A wakelock is used to resist Android's doze. This state should be active
|
||||
// while out and about.
|
||||
Log.i("VOUSSOIR", "TrackerService.state_full_power")
|
||||
tracking_state = Keys.STATE_FULL_RECORDING
|
||||
PreferencesHelper.saveTrackingState(tracking_state)
|
||||
reset_location_listeners(Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
arrived_at_home = 0
|
||||
gave_up_at = 0
|
||||
if (foreground_started == 0L)
|
||||
{
|
||||
startForeground(Keys.TRACKER_SERVICE_NOTIFICATION_ID, displayNotification())
|
||||
foreground_started = System.currentTimeMillis()
|
||||
}
|
||||
if (gpsLocationListenerRegistered || networkLocationListenerRegistered)
|
||||
{
|
||||
start_wakelock()
|
||||
}
|
||||
else
|
||||
{
|
||||
state_dead()
|
||||
}
|
||||
displayNotification()
|
||||
}
|
||||
fun state_arrived_at_home()
|
||||
{
|
||||
// This state is activated when the user enters the radius of a homepoint. The GPS will
|
||||
// remain at full power for a few minutes before we transition to sleep.
|
||||
Log.i("VOUSSOIR", "TrackerService.state_arrived_at_home")
|
||||
tracking_state = Keys.STATE_ARRIVED_AT_HOME
|
||||
PreferencesHelper.saveTrackingState(tracking_state)
|
||||
reset_location_listeners(Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
trackbook.database.commit()
|
||||
arrived_at_home = System.currentTimeMillis()
|
||||
gave_up_at = 0
|
||||
stop_wakelock()
|
||||
displayNotification()
|
||||
}
|
||||
fun state_sleep()
|
||||
{
|
||||
// This state is activated when the user stays at a homepoint for several minutes. It will
|
||||
// be woken up again by the acceleromters or by plugging / unplugging power.
|
||||
Log.i("VOUSSOIR", "TrackerService.state_sleep")
|
||||
tracking_state = Keys.STATE_SLEEP
|
||||
PreferencesHelper.saveTrackingState(tracking_state)
|
||||
reset_location_listeners(Keys.LOCATION_INTERVAL_SLEEP)
|
||||
arrived_at_home = arrived_at_home
|
||||
gave_up_at = 0
|
||||
stop_wakelock()
|
||||
displayNotification()
|
||||
}
|
||||
fun state_dead()
|
||||
{
|
||||
// This state is activated when the device is struggling to receive a GPS fix due to being
|
||||
// indoors / underground. It will be woken up again by the accelerometers or by plugging /
|
||||
// unplugging power.
|
||||
Log.i("VOUSSOIR", "TrackerService.state_dead")
|
||||
tracking_state = Keys.STATE_DEAD
|
||||
PreferencesHelper.saveTrackingState(tracking_state)
|
||||
reset_location_listeners(Keys.LOCATION_INTERVAL_STOP)
|
||||
trackbook.database.commit()
|
||||
recent_displacement_locations.clear()
|
||||
arrived_at_home = 0
|
||||
gave_up_at = System.currentTimeMillis()
|
||||
stop_wakelock()
|
||||
displayNotification()
|
||||
}
|
||||
fun state_mapview()
|
||||
{
|
||||
// This state should be activated when the user has the app open to the mapfragment, but is
|
||||
// not recording. If the user closes the app while in this state, we can go to stop.
|
||||
Log.i("VOUSSOIR", "TrackerService.state_mapview")
|
||||
tracking_state = Keys.STATE_MAPVIEW
|
||||
PreferencesHelper.saveTrackingState(tracking_state)
|
||||
reset_location_listeners(Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
arrived_at_home = 0
|
||||
gave_up_at = 0
|
||||
stop_wakelock()
|
||||
displayNotification()
|
||||
if (!gpsLocationListenerRegistered && !networkLocationListenerRegistered)
|
||||
{
|
||||
state_dead()
|
||||
}
|
||||
}
|
||||
|
||||
fun start_wakelock()
|
||||
{
|
||||
if (!wakelock.isHeld)
|
||||
{
|
||||
wakelock.acquire()
|
||||
}
|
||||
}
|
||||
|
||||
fun stop_wakelock()
|
||||
{
|
||||
if (wakelock.isHeld)
|
||||
{
|
||||
wakelock.release()
|
||||
}
|
||||
}
|
||||
|
||||
fun reset_location_listeners(interval: Long)
|
||||
{
|
||||
Log.i("VOUSSOIR", "TrackerService.reset_location_listeners")
|
||||
location_interval = interval
|
||||
if (use_gps_location && interval != Keys.LOCATION_INTERVAL_DEAD && interval != Keys.LOCATION_INTERVAL_STOP)
|
||||
if (use_gps_location && interval != Keys.LOCATION_INTERVAL_STOP)
|
||||
{
|
||||
addGpsLocationListener(interval)
|
||||
add_gps_location_listener(interval)
|
||||
}
|
||||
else if (gpsLocationListenerRegistered)
|
||||
{
|
||||
removeGpsLocationListener()
|
||||
remove_gps_location_listener()
|
||||
}
|
||||
if (use_network_location && interval != Keys.LOCATION_INTERVAL_DEAD && interval != Keys.LOCATION_INTERVAL_STOP)
|
||||
if (use_network_location && interval != Keys.LOCATION_INTERVAL_STOP)
|
||||
{
|
||||
addNetworkLocationListener(interval)
|
||||
add_network_location_listener(interval)
|
||||
}
|
||||
else if (networkLocationListenerRegistered)
|
||||
{
|
||||
removeNetworkLocationListener()
|
||||
}
|
||||
|
||||
if (interval != Keys.LOCATION_INTERVAL_DEAD)
|
||||
{
|
||||
gave_up_at = 0
|
||||
remove_network_location_listener()
|
||||
}
|
||||
|
||||
if (gpsLocationListenerRegistered || networkLocationListenerRegistered)
|
||||
{
|
||||
listeners_enabled_at = System.currentTimeMillis()
|
||||
if (interval != Keys.LOCATION_INTERVAL_SLEEP)
|
||||
{
|
||||
arrived_at_home = 0
|
||||
}
|
||||
}
|
||||
else if (interval == Keys.LOCATION_INTERVAL_STOP)
|
||||
{
|
||||
listeners_enabled_at = 0
|
||||
}
|
||||
else
|
||||
{
|
||||
listeners_enabled_at = 0
|
||||
location_interval = Keys.LOCATION_INTERVAL_DEAD
|
||||
}
|
||||
|
||||
val should_wakelock = (
|
||||
(gpsLocationListenerRegistered || networkLocationListenerRegistered) &&
|
||||
trackingState == Keys.STATE_TRACKING_ACTIVE &&
|
||||
interval == Keys.LOCATION_INTERVAL_FULL_POWER
|
||||
)
|
||||
if (should_wakelock)
|
||||
{
|
||||
if (! wakelock.isHeld)
|
||||
{
|
||||
wakelock.acquire()
|
||||
}
|
||||
}
|
||||
else if (wakelock.isHeld)
|
||||
{
|
||||
wakelock.release()
|
||||
}
|
||||
|
||||
displayNotification()
|
||||
}
|
||||
|
||||
|
@ -253,10 +357,11 @@ class TrackerService: Service()
|
|||
|
||||
currentBestLocation = location
|
||||
|
||||
if (trackingState != Keys.STATE_TRACKING_ACTIVE)
|
||||
if (tracking_state == Keys.STATE_STOP || tracking_state == Keys.STATE_MAPVIEW)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
if(! trackbook.database.ready)
|
||||
{
|
||||
Log.i("VOUSSOIR", "Omitting due to database not ready.")
|
||||
|
@ -283,34 +388,43 @@ class TrackerService: Service()
|
|||
continue
|
||||
}
|
||||
Log.i("VOUSSOIR", "Omitting due to homepoint ${index} ${homepoint.name}.")
|
||||
|
||||
// Move this homepoint to the front of the list so that on subsequent location
|
||||
// updates it hits on the first loop. I'm sure this is a trivial amount of
|
||||
// savings but oh well.
|
||||
if (index > 0)
|
||||
{
|
||||
trackbook.homepoints.remove(homepoint)
|
||||
trackbook.homepoints.addFirst(homepoint)
|
||||
}
|
||||
if (arrived_at_home == 0L)
|
||||
if (tracking_state != Keys.STATE_ARRIVED_AT_HOME && tracking_state != Keys.STATE_SLEEP)
|
||||
{
|
||||
Log.i("VOUSSOIR", "Arrived at home.")
|
||||
arrived_at_home = System.currentTimeMillis()
|
||||
trackbook.database.commit()
|
||||
state_arrived_at_home()
|
||||
}
|
||||
else if (
|
||||
allow_sleep &&
|
||||
has_motion_sensor &&
|
||||
location_interval != Keys.LOCATION_INTERVAL_SLEEP &&
|
||||
tracking_state == Keys.STATE_ARRIVED_AT_HOME &&
|
||||
(System.currentTimeMillis() - arrived_at_home) > TIME_UNTIL_SLEEP &&
|
||||
(System.currentTimeMillis() - last_significant_motion) > TIME_UNTIL_SLEEP
|
||||
)
|
||||
{
|
||||
Log.i("VOUSSOIR", "Staying at home, sleeping.")
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_SLEEP)
|
||||
state_sleep()
|
||||
}
|
||||
return
|
||||
}
|
||||
if (arrived_at_home > 0)
|
||||
|
||||
// All of the homepoint checks failed so we have left home and it's time to wake up.
|
||||
// In practice we expect that the accelerometers would have triggered this change
|
||||
// already, but this acts as a backup in case you somehow leave home without too
|
||||
// much movement (maybe you sat in the car for several minutes before finally
|
||||
// driving away or something).
|
||||
if (tracking_state == Keys.STATE_ARRIVED_AT_HOME || tracking_state == Keys.STATE_SLEEP)
|
||||
{
|
||||
Log.i("VOUSSOIR", "Leaving home.")
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
state_full_recording()
|
||||
}
|
||||
|
||||
if (! isRecentEnough(location))
|
||||
|
@ -351,10 +465,10 @@ class TrackerService: Service()
|
|||
recent_displacement_locations.removeFirst()
|
||||
}
|
||||
|
||||
if (location.time - lastCommit > Keys.COMMIT_INTERVAL)
|
||||
if ((location.time - last_commit) > Keys.COMMIT_INTERVAL)
|
||||
{
|
||||
trackbook.database.commit()
|
||||
lastCommit = location.time
|
||||
last_commit = location.time
|
||||
}
|
||||
}
|
||||
override fun onProviderEnabled(provider: String)
|
||||
|
@ -385,43 +499,34 @@ class TrackerService: Service()
|
|||
}
|
||||
|
||||
val timestamp = iso8601_local_noms(currentBestLocation.time)
|
||||
if (trackingState == Keys.STATE_TRACKING_ACTIVE)
|
||||
if (tracking_state == Keys.STATE_FULL_RECORDING)
|
||||
{
|
||||
notification_builder.setContentTitle(this.getString(R.string.notification_title_trackbook_running))
|
||||
if (location_interval == Keys.LOCATION_INTERVAL_FULL_POWER && arrived_at_home > 0)
|
||||
{
|
||||
notification_builder.setContentTitle("${timestamp} (home)")
|
||||
notification_builder.setSmallIcon(R.drawable.ic_satellite_24dp)
|
||||
}
|
||||
else if (location_interval == Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
{
|
||||
notification_builder.setContentTitle("${timestamp} (recording)")
|
||||
notification_builder.setSmallIcon(R.drawable.ic_satellite_24dp)
|
||||
}
|
||||
else if (location_interval == Keys.LOCATION_INTERVAL_SLEEP)
|
||||
{
|
||||
notification_builder.setContentTitle("${timestamp} (sleeping)")
|
||||
notification_builder.setSmallIcon(R.drawable.ic_sleep_24dp)
|
||||
}
|
||||
else if (location_interval == Keys.LOCATION_INTERVAL_DEAD)
|
||||
{
|
||||
notification_builder.setContentTitle("${timestamp} (dead)")
|
||||
notification_builder.setSmallIcon(R.drawable.ic_skull_24dp)
|
||||
}
|
||||
else
|
||||
{
|
||||
notification_builder.setContentText(timestamp)
|
||||
notification_builder.setSmallIcon(R.drawable.ic_fiber_manual_record_inactive_24dp)
|
||||
}
|
||||
notification_builder.setContentTitle("${timestamp} (recording)")
|
||||
notification_builder.setSmallIcon(R.drawable.ic_satellite_24dp)
|
||||
}
|
||||
else
|
||||
else if (tracking_state == Keys.STATE_ARRIVED_AT_HOME)
|
||||
{
|
||||
notification_builder.setContentTitle("${timestamp} (home)")
|
||||
notification_builder.setSmallIcon(R.drawable.ic_homepoint_24dp)
|
||||
}
|
||||
else if (tracking_state == Keys.STATE_SLEEP)
|
||||
{
|
||||
notification_builder.setContentTitle("${timestamp} (sleeping)")
|
||||
notification_builder.setSmallIcon(R.drawable.ic_sleep_24dp)
|
||||
}
|
||||
else if (tracking_state == Keys.STATE_DEAD)
|
||||
{
|
||||
notification_builder.setContentTitle("${timestamp} (dead)")
|
||||
notification_builder.setSmallIcon(R.drawable.ic_skull_24dp)
|
||||
}
|
||||
else if (tracking_state == Keys.STATE_STOP || tracking_state == Keys.STATE_MAPVIEW)
|
||||
{
|
||||
notification_builder.setContentTitle("${timestamp} (stopped)")
|
||||
notification_builder.setSmallIcon(R.drawable.ic_fiber_manual_stop_24dp)
|
||||
}
|
||||
|
||||
val notification = notification_builder.build()
|
||||
notificationManager.notify(Keys.TRACKER_SERVICE_NOTIFICATION_ID, notification)
|
||||
notification_manager.notify(Keys.TRACKER_SERVICE_NOTIFICATION_ID, notification)
|
||||
return notification
|
||||
}
|
||||
|
||||
|
@ -430,7 +535,7 @@ class TrackerService: Service()
|
|||
|
||||
/* Checks if notification channel exists */
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private fun nowPlayingChannelExists() = notificationManager.getNotificationChannel(Keys.NOTIFICATION_CHANNEL_RECORDING) != null
|
||||
private fun nowPlayingChannelExists() = notification_manager.getNotificationChannel(Keys.NOTIFICATION_CHANNEL_RECORDING) != null
|
||||
|
||||
/* Create a notification channel */
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
|
@ -441,18 +546,21 @@ class TrackerService: Service()
|
|||
this.getString(R.string.notification_channel_recording_name),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
).apply { description = this@TrackerService.getString(R.string.notification_channel_recording_description) }
|
||||
notificationManager.createNotificationChannel(notificationChannel)
|
||||
notification_manager.createNotificationChannel(notificationChannel)
|
||||
}
|
||||
|
||||
/* Overrides onBind from Service */
|
||||
override fun onBind(p0: Intent?): IBinder
|
||||
{
|
||||
Log.i("VOUSSOIR", "TrackerService.onBind")
|
||||
if (listeners_enabled_at == 0L && location_interval != Keys.LOCATION_INTERVAL_DEAD)
|
||||
if (tracking_state == Keys.STATE_STOP)
|
||||
{
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
state_mapview()
|
||||
}
|
||||
else
|
||||
{
|
||||
displayNotification()
|
||||
}
|
||||
displayNotification()
|
||||
bound = true
|
||||
return binder
|
||||
}
|
||||
|
@ -461,11 +569,14 @@ class TrackerService: Service()
|
|||
override fun onRebind(intent: Intent?)
|
||||
{
|
||||
Log.i("VOUSSOIR", "TrackerService.onRebind")
|
||||
if (listeners_enabled_at == 0L && location_interval != Keys.LOCATION_INTERVAL_DEAD)
|
||||
if (tracking_state == Keys.STATE_STOP)
|
||||
{
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
state_mapview()
|
||||
}
|
||||
else
|
||||
{
|
||||
displayNotification()
|
||||
}
|
||||
displayNotification()
|
||||
bound = true
|
||||
}
|
||||
|
||||
|
@ -475,10 +586,11 @@ class TrackerService: Service()
|
|||
super.onUnbind(intent)
|
||||
Log.i("VOUSSOIR", "TrackerService.onUnbind")
|
||||
bound = false
|
||||
// stop receiving location updates - if not tracking
|
||||
if (trackingState != Keys.STATE_TRACKING_ACTIVE)
|
||||
|
||||
// the user was only perusing the map and did not start recording, so we'll just stop.
|
||||
if (tracking_state == Keys.STATE_MAPVIEW)
|
||||
{
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_STOP)
|
||||
state_stop()
|
||||
}
|
||||
// ensures onRebind is called
|
||||
return true
|
||||
|
@ -498,9 +610,10 @@ class TrackerService: Service()
|
|||
device_id = PreferencesHelper.load_device_id()
|
||||
useImperial = PreferencesHelper.loadUseImperialUnits()
|
||||
omitRests = PreferencesHelper.loadOmitRests()
|
||||
max_accuracy = PreferencesHelper.load_max_accuracy()
|
||||
allow_sleep = PreferencesHelper.loadAllowSleep()
|
||||
locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notification_manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notification_builder = NotificationCompat.Builder(this, Keys.NOTIFICATION_CHANNEL_RECORDING)
|
||||
val showActionPendingIntent: PendingIntent? = TaskStackBuilder.create(this).run {
|
||||
addNextIntentWithParentStack(Intent(this@TrackerService, MainActivity::class.java))
|
||||
|
@ -512,7 +625,6 @@ class TrackerService: Service()
|
|||
networkProviderActive = isNetworkEnabled(locationManager)
|
||||
gpsLocationListener = createLocationListener()
|
||||
networkLocationListener = createLocationListener()
|
||||
trackingState = PreferencesHelper.loadTrackingState()
|
||||
currentBestLocation = getLastKnownLocation(this)
|
||||
PreferencesHelper.registerPreferenceChangeListener(sharedPreferenceChangeListener)
|
||||
|
||||
|
@ -526,10 +638,10 @@ class TrackerService: Service()
|
|||
override fun onTrigger(event: TriggerEvent?) {
|
||||
Log.i("VOUSSOIR", "Significant motion")
|
||||
last_significant_motion = System.currentTimeMillis()
|
||||
if (trackingState == Keys.STATE_TRACKING_ACTIVE && location_interval != Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
if (tracking_state == Keys.STATE_SLEEP || tracking_state == Keys.STATE_DEAD)
|
||||
{
|
||||
vibrator.vibrate(100)
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
state_full_recording()
|
||||
}
|
||||
sensor_manager.requestTriggerSensor(this, significant_motion_sensor)
|
||||
}
|
||||
|
@ -546,11 +658,10 @@ class TrackerService: Service()
|
|||
override fun onSensorChanged(event: SensorEvent?) {
|
||||
Log.i("VOUSSOIR", "Step counter changed")
|
||||
last_significant_motion = System.currentTimeMillis()
|
||||
if (trackingState == Keys.STATE_TRACKING_ACTIVE && location_interval != Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
if (tracking_state == Keys.STATE_SLEEP || tracking_state == Keys.STATE_DEAD)
|
||||
{
|
||||
// beeper.startTone(ToneGenerator.TONE_PROP_ACK, 150)
|
||||
vibrator.vibrate(100)
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
state_full_recording()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -574,9 +685,9 @@ class TrackerService: Service()
|
|||
{
|
||||
device_is_charging = false
|
||||
}
|
||||
if (trackingState == Keys.STATE_TRACKING_ACTIVE)
|
||||
if (tracking_state == Keys.STATE_SLEEP || tracking_state == Keys.STATE_DEAD)
|
||||
{
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
state_full_recording()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -588,6 +699,7 @@ class TrackerService: Service()
|
|||
val powermanager = getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||
wakelock = powermanager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "trkpt::wakelock")
|
||||
|
||||
load_tracking_state()
|
||||
handler.post(background_watchdog)
|
||||
}
|
||||
|
||||
|
@ -599,19 +711,19 @@ class TrackerService: Service()
|
|||
// SERVICE RESTART (via START_STICKY)
|
||||
if (intent == null)
|
||||
{
|
||||
if (trackingState == Keys.STATE_TRACKING_ACTIVE)
|
||||
if (tracking_state != Keys.STATE_STOP && tracking_state != Keys.STATE_MAPVIEW)
|
||||
{
|
||||
Log.w("VOUSSOIR", "Trackbook has been killed by the operating system. Trying to resume recording.")
|
||||
startTracking()
|
||||
state_full_recording()
|
||||
}
|
||||
}
|
||||
else if (intent.action == Keys.ACTION_STOP)
|
||||
{
|
||||
stopTracking()
|
||||
state_stop()
|
||||
}
|
||||
else if (intent.action == Keys.ACTION_START)
|
||||
{
|
||||
startTracking()
|
||||
state_full_recording()
|
||||
}
|
||||
|
||||
// START_STICKY is used for services that are explicitly started and stopped as needed
|
||||
|
@ -623,51 +735,24 @@ class TrackerService: Service()
|
|||
{
|
||||
Log.i("VOUSSOIR", "TrackerService.onDestroy.")
|
||||
super.onDestroy()
|
||||
if (trackingState == Keys.STATE_TRACKING_ACTIVE)
|
||||
{
|
||||
stopTracking()
|
||||
}
|
||||
stopForeground(STOP_FOREGROUND_REMOVE)
|
||||
state_stop()
|
||||
PreferencesHelper.unregisterPreferenceChangeListener(sharedPreferenceChangeListener)
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_DEAD)
|
||||
handler.removeCallbacks(background_watchdog)
|
||||
unregisterReceiver(charging_broadcast_receiver)
|
||||
}
|
||||
|
||||
fun startTracking()
|
||||
{
|
||||
Log.i("VOUSSOIR", "TrackerService.startTracking")
|
||||
trackingState = Keys.STATE_TRACKING_ACTIVE
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
PreferencesHelper.saveTrackingState(trackingState)
|
||||
recent_displacement_locations.clear()
|
||||
startForeground(Keys.TRACKER_SERVICE_NOTIFICATION_ID, displayNotification())
|
||||
}
|
||||
|
||||
fun stopTracking()
|
||||
{
|
||||
Log.i("VOUSSOIR", "TrackerService.stopTracking")
|
||||
trackbook.database.commit()
|
||||
trackingState = Keys.STATE_TRACKING_STOPPED
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
PreferencesHelper.saveTrackingState(trackingState)
|
||||
recent_displacement_locations.clear()
|
||||
displayNotification()
|
||||
stopForeground(STOP_FOREGROUND_DETACH)
|
||||
}
|
||||
|
||||
private val sharedPreferenceChangeListener = SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
|
||||
when (key)
|
||||
{
|
||||
Keys.PREF_LOCATION_GPS ->
|
||||
{
|
||||
use_gps_location = PreferencesHelper.load_location_gps()
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
state_full_recording()
|
||||
}
|
||||
Keys.PREF_LOCATION_NETWORK ->
|
||||
{
|
||||
use_network_location = PreferencesHelper.load_location_network()
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
state_full_recording()
|
||||
}
|
||||
Keys.PREF_USE_IMPERIAL_UNITS ->
|
||||
{
|
||||
|
@ -684,9 +769,9 @@ class TrackerService: Service()
|
|||
Keys.PREF_ALLOW_SLEEP ->
|
||||
{
|
||||
allow_sleep = PreferencesHelper.loadAllowSleep()
|
||||
if (! allow_sleep && trackingState == Keys.STATE_TRACKING_ACTIVE && location_interval != Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
if (! allow_sleep && (tracking_state == Keys.STATE_SLEEP || tracking_state == Keys.STATE_DEAD))
|
||||
{
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_FULL_POWER)
|
||||
state_full_recording()
|
||||
}
|
||||
}
|
||||
Keys.PREF_DEVICE_ID ->
|
||||
|
@ -723,21 +808,19 @@ class TrackerService: Service()
|
|||
has_motion_sensor &&
|
||||
!device_is_charging &&
|
||||
// We only go to dead during active tracking because if you are looking at the
|
||||
// device in non-tracking mode you are probably waiting for your signal to recover.
|
||||
trackingState == Keys.STATE_TRACKING_ACTIVE &&
|
||||
// device in mapview state you are probably waiting for your signal to recover.
|
||||
// We only go to dead from full power because in the sleep state, the wakelock is
|
||||
// turned off and the device may go into doze. During doze, the device stops
|
||||
// updating the location listeners anyway, so there is no benefit in going to dead.
|
||||
// When the user interacts with the device and it leaves doze, it's better to come
|
||||
// from sleep state than dead state.
|
||||
location_interval == Keys.LOCATION_INTERVAL_FULL_POWER &&
|
||||
tracking_state == Keys.STATE_FULL_RECORDING &&
|
||||
(now - listeners_enabled_at) > TIME_UNTIL_DEAD &&
|
||||
(now - currentBestLocation.time) > TIME_UNTIL_DEAD &&
|
||||
(now - last_significant_motion) > TIME_UNTIL_DEAD
|
||||
)
|
||||
{
|
||||
reset_location_listeners(interval=Keys.LOCATION_INTERVAL_DEAD)
|
||||
gave_up_at = now
|
||||
state_dead()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* TrackingToggleTileService.kt
|
||||
* Implements the TrackingToggleTileService service
|
||||
* A TrackingToggleTileService toggles the recording state from a quick settings tile
|
||||
*
|
||||
* This file is part of
|
||||
* TRACKBOOK - Movement Recorder for Android
|
||||
*
|
||||
* Copyright (c) 2016-22 - Y20K.org
|
||||
* Licensed under the MIT-License
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* Trackbook uses osmdroid - OpenStreetMap-Tools for Android
|
||||
* https://github.com/osmdroid/osmdroid
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by voussoir for trkpt, forked from Trackbook.
|
||||
*/
|
||||
|
||||
package net.voussoir.trkpt
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.Build
|
||||
import android.service.quicksettings.Tile
|
||||
import android.service.quicksettings.TileService
|
||||
import net.voussoir.trkpt.helpers.PreferencesHelper
|
||||
|
||||
/*
|
||||
* TrackingToggleTileService class
|
||||
*/
|
||||
class TrackingToggleTileService: TileService()
|
||||
{
|
||||
/* Main class variables */
|
||||
private var bound: Boolean = false
|
||||
private var trackingState: Int = Keys.STATE_TRACKING_STOPPED
|
||||
private lateinit var trackerService: TrackerService
|
||||
|
||||
/* Overrides onTileAdded from TileService */
|
||||
override fun onTileAdded() {
|
||||
super.onTileAdded()
|
||||
// get saved tracking state
|
||||
trackingState = PreferencesHelper.loadTrackingState()
|
||||
// set up tile
|
||||
updateTile()
|
||||
}
|
||||
|
||||
/* Overrides onTileRemoved from TileService */
|
||||
override fun onTileRemoved() {
|
||||
super.onTileRemoved()
|
||||
}
|
||||
|
||||
/* Overrides onStartListening from TileService (tile becomes visible) */
|
||||
override fun onStartListening() {
|
||||
super.onStartListening()
|
||||
// get saved tracking state
|
||||
trackingState = PreferencesHelper.loadTrackingState()
|
||||
// set up tile
|
||||
updateTile()
|
||||
// register listener for changes in shared preferences
|
||||
PreferencesHelper.registerPreferenceChangeListener(sharedPreferenceChangeListener)
|
||||
}
|
||||
|
||||
/* Overrides onClick from TileService */
|
||||
override fun onClick() {
|
||||
super.onClick()
|
||||
when (trackingState) {
|
||||
Keys.STATE_TRACKING_ACTIVE -> stopTracking()
|
||||
else -> startTracking()
|
||||
}
|
||||
}
|
||||
|
||||
/* Overrides onStopListening from TileService (tile no longer visible) */
|
||||
override fun onStopListening() {
|
||||
super.onStopListening()
|
||||
// unregister listener for changes in shared preferences
|
||||
PreferencesHelper.unregisterPreferenceChangeListener(sharedPreferenceChangeListener)
|
||||
}
|
||||
|
||||
/* Overrides onDestroy from Service */
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
/* Update quick settings tile */
|
||||
private fun updateTile() {
|
||||
val tile: Tile = qsTile
|
||||
tile.icon = Icon.createWithResource(this, R.drawable.ic_notification_icon_small_24dp)
|
||||
when (trackingState) {
|
||||
Keys.STATE_TRACKING_ACTIVE -> {
|
||||
tile.label = getString(R.string.quick_settings_tile_title_pause)
|
||||
tile.contentDescription = getString(R.string.descr_quick_settings_tile_title_pause)
|
||||
tile.state = Tile.STATE_ACTIVE
|
||||
}
|
||||
else -> {
|
||||
tile.label = getString(R.string.quick_settings_tile_title_start)
|
||||
tile.contentDescription = getString(R.string.descr_quick_settings_tile_title_start)
|
||||
tile.state = Tile.STATE_INACTIVE
|
||||
}
|
||||
}
|
||||
tile.updateTile()
|
||||
}
|
||||
|
||||
/* Start tracking */
|
||||
private fun startTracking() {
|
||||
val intent = Intent(application, TrackerService::class.java)
|
||||
intent.action = Keys.ACTION_START
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// ... start service in foreground to prevent it being killed on Oreo
|
||||
application.startForegroundService(intent)
|
||||
} else {
|
||||
application.startService(intent)
|
||||
}
|
||||
}
|
||||
|
||||
/* Stop tracking */
|
||||
private fun stopTracking() {
|
||||
val intent = Intent(application, TrackerService::class.java)
|
||||
intent.action = Keys.ACTION_STOP
|
||||
application.startService(intent)
|
||||
}
|
||||
|
||||
/*
|
||||
* Defines the listener for changes in shared preferences
|
||||
*/
|
||||
private val sharedPreferenceChangeListener = SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
|
||||
when (key) {
|
||||
Keys.PREF_TRACKING_STATE -> {
|
||||
trackingState = PreferencesHelper.loadTrackingState()
|
||||
updateTile()
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* End of declaration
|
||||
*/
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -75,7 +75,7 @@ object PreferencesHelper
|
|||
}
|
||||
|
||||
fun loadTrackingState(): Int {
|
||||
return sharedPreferences.getInt(Keys.PREF_TRACKING_STATE, Keys.STATE_TRACKING_STOPPED)
|
||||
return sharedPreferences.getInt(Keys.PREF_TRACKING_STATE, Keys.STATE_STOP)
|
||||
}
|
||||
|
||||
fun saveTrackingState(trackingState: Int) {
|
||||
|
|
|
@ -30,6 +30,7 @@ import net.voussoir.trkpt.Keys
|
|||
import net.voussoir.trkpt.R
|
||||
import net.voussoir.trkpt.Database
|
||||
import net.voussoir.trkpt.Track
|
||||
import net.voussoir.trkpt.helpers.PreferencesHelper
|
||||
import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
@ -53,9 +54,10 @@ class TracklistAdapter(val fragment: Fragment, val database: Database) : Recycle
|
|||
{
|
||||
return
|
||||
}
|
||||
val max_accuracy = PreferencesHelper.load_max_accuracy()
|
||||
val cursor: Cursor = database.connection.rawQuery(
|
||||
"SELECT distinct(date(time/1000, 'unixepoch', 'localtime')) as thedate, device_id FROM trkpt ORDER BY thedate DESC",
|
||||
arrayOf()
|
||||
"SELECT distinct(date(time/1000, 'unixepoch', 'localtime')) as thedate, device_id FROM trkpt WHERE accuracy <= ? ORDER BY thedate DESC",
|
||||
arrayOf(max_accuracy.toString())
|
||||
)
|
||||
try
|
||||
{
|
||||
|
|
|
@ -91,7 +91,7 @@
|
|||
<string name="pref_advanced_title">Advanced</string>
|
||||
<string name="pref_delete_non_starred_summary">Delete all recordings in \"Tracks\" that are not starred.</string>
|
||||
<string name="pref_delete_non_starred_title">Delete Non-Starred Recordings</string>
|
||||
<string name="pref_general_title">General</string>
|
||||
<string name="pref_general_title">Settings</string>
|
||||
<string name="pref_maintenance_title">Maintenance</string>
|
||||
<string name="pref_location_gps_title">Use GPS location</string>
|
||||
<string name="pref_location_gps_summary_on">GPS location enabled.</string>
|
||||
|
|
Loading…
Reference in a new issue